company_banner

Кунг-фу стиля Linux: удобная работа с файлами по SSH

Автор оригинала: Al Williams
  • Перевод
Если у вас имеется больше одного 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 позволяют организовать более быструю работу с соединениями, что, в нашем случае, очень важно.

Кроме того, можно организовать автоматическое подключение к удалённой системе с использованием приватных ssh-ключей. Вот материал об этом.

Скрипт


Наш скрипт можно использовать двумя способами. Так, если его вызывают через ссылку к sshunmount, то он размонтирует файловую систему, связанную с указанным удалённым хостом. Если его вызывают иначе (обычно — как sshmount), то он выполняет следующие три действия:

  1. Он проверяет, есть ли в директории ~/remote поддиректория, имя которой совпадает с именем хоста (например — lab). Если такой директории нет — он выводит сообщение об ошибке и продолжает работу.
  2. Если такая директория существует — скрипт просматривает список смонтированных файловых систем на тот случай, если нужная файловая система уже смонтирована. Если это так — он продолжает работу.
  3. Если директория не смонтирована — он вызывает 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-систем?



RUVDS.com
VDS/VPS-хостинг. Скидка 10% по коду HABR

Комментарии 36

    +5
    sshfs через более-менее неустойчивое соединение(обычное для домовых провайдеров) это верный способ отстрелить себе ногу.

    Даже ftpfs работает стабильнее.

    А вообще для решения данной задачи есть же filezilla-project.org
      0

      А разве Файлзилла умеет монтировать? Мне казалось, это только GUI-клиент для FTP/SCP — разве не так?

        0
        Всё так.
      +4
      Если необходимо что-то быстро поправить на удаленном сервере, то я пользуюсь krusader — новое сетевое подключение. И в нем настроено, что по F4 редактировать файлы в kate. При сохранении файла он сохраняется на сервере.

      Под windows для этой же цели можно использовать winscp и любой редактор по вкусу. Подойдет даже VS Code.
        +4

        Visual code — наверное лучший редактор на платформах win и linux. И в нем есть отличный плагин sshfs, с помощью которого можно настроить кучу коннектов и удобно работать с различными рабочими пространствами. Если хочется все и в одном окне, то в нем же есть терминал

          0

          Надо будет посмотреть, а то встроенный Remote-SSH запускает на удалённом сервере nodejs со всеми плагинами.

            0

            В emacs это тоже есть прямо из коробки. Достаточно открыть "файл" вида /ssh:user@server:path/to/file. В случае разрыва связи ничего не поломается, при попытке сохранить емакс сам восстановит соединение.

              0
              У данного плагина есть ряд особенностей. Да и вообще удалённой работы с файлами из VS. По работе много приходилось кодить на удалённых серверах. И вот без плагина на стороне сервера, это всё очень плохо работает. Особенно поиски по файлам. Открытие больших файлов (тот же vim переваривает под несколько гигов файл). Так что своеобразные впечатления.
                0
                ну, кодить прямо на удаленном сервере — плохая идея почти всегда. Но тоже приходилось править код и тут он справляется прекрасно. Большие файлы в визуал коде в целом не очень хорошо работают, но каких-то сложностей с плагином не заметил ( а может и не открывал). Если файл большой, то как правило используются другие средства для его обработки
            +3
            Как альтернатива — набор инструментов:
            Редактирование текстовых файлов (встроенный внешний редактор), копирование файлов: winscp
            Для консоли: PuTTY
            Запуск X-приложений (X-сервер): xming
              +1
              Бесплатная версия Xming древняя и багованная, а за обновленную разработчик просит требует донат в размере 10 GBP (1к рублей), еще и сроком действия в один год.
              Советую VcXsrv sourceforge.net/projects/vcxsrv
                0
                Спасибо, попробую.
              –8
              alias sshmount='echo youpassword | sshfs nikname@server:/ ~/ssh -o password_stdin'

              и всех делов
                +5

                Авторизация по ключам же, и не нужно вот этого всего хранения паролей в открытом виде в куче скриптов. См. ssh-copy-id и ~/.ssh/authorized_keys. Еще и серверы от брутфорса пароля будут защищены.


                Один раз создал ssh-ключ, раскидал публичный ключ на все нужные серверы и никаких проблем с авторизацией. Если ssh-ключ с паролем, то его достаточно разблокировать единожды, многие DE имеют keyring и ключик надо разблокировать только при первом использовании.

                  +6
                  Плохой, негодный совет. Нет, я понимаю, бывают железки на которых либо нет авторизации по ключу, либо их поставить туда просто нельзя, по разным причинам. Но такой совет будет светить паролем в списке процессов и в
                  .*history
                  . Лучше уж либо через переменную скармливать, а ещё лучше использовать
                  sshpass
                  +8
                  Файловые менеджеры в современных Линукс дистирбутивах поддерживают SFTP из коробки. Т.е. можно открывать удалённые директории по адресу sftp://user@host/path/to/directory.
                    +1
                    В не очень современных mc поддерживал это… ну почти всегда.
                    +2
                    Ещё sshfs можно автоматизировать с помощью autofs или /etc/fstab
                      +1

                      Или systemd automount.

                        +2
                        Я у себя избавился от записей в fstab. Всё перенёс в экосистему sysytemd (*.mount; *.automount) что немного ускорило загрузку системы (systemd не занимается автогенерацией рантайм *.mount файлов из содержимого fstab) ну и бонусом всякие /boot и /boot/efi на автомонтировании, ибо они нужны смонтированными только в момент загрузки системы или в момент обновления ядер или grub. Ну и облака тоже на автомаунте. Достаточно обратиться к каталогу куда смонтирован какой-нить яндекс и вумная железка сделает всё остальное. А через пять минут после последнего обращения к каталогу произойдёт отмонтирование.
                          +2
                          хмм, ускорение загрузки системы заметное? Просто сам man systemd.mount пишет:
                          In general, configuring mount points through /etc/fstab is the preferred approach.


                          поэтому я по-старинке делаю. И ещё у меня авто-отмонтирование не заработало — может быть, из-за этого?
                            0

                            У меня обычное монтирование, через /etc/fstab — при недоступности домашней файлопомойки загрузка по ощущениям длится на минуту-другую дольше — задержка возникает как раз при попытке монтирования недоступного.

                              0
                              Почитайте вот этот мой ответ. Ну и вам пример. У меня облако, у вас там наверное будет маунт с SMB или NFS.
                              /etc/systemd/system/yadisk.mount
                              [Unit]
                              Description=Yandex disk automounted drive
                              Documentation=man:systemd.mount(8)

                              [Mount]
                              Where=/home/oxyd/Clouds/yadisk
                              What=https://webdav.yandex.ru/
                              Type=davfs
                              Options=noauto,user

                              /etc/systemd/system/yadisk.automount
                              [Unit]
                              Description=Automount yandex disc when needed.

                              [Automount]
                              Where=/home/oxyd/Clouds/yadisk
                              ## Time to automatic umount of inactivity
                              TimeoutIdleSec=300

                              [Install]
                              WantedBy=multi-user.target
                              0
                              Видимо вы что-то не так делали. Любые разделы, кроме корневого(а так-же /usr если он вынесен в отдельный раздел) прекрасно выносятся, без лишних телодвижений, в соответствующие *.mount файлы, которые надо положить в /etc/systemd/system. Для корневого и /usr(если есть) нужно не только создать *.mount но и добавить параметры ядра из man systemd-fstab-generator, что-бы система на раннем уровне загрузки смогла смонтировать /usr и /. Там-же параметр который полностью отключает автогенерацию *.mount и *.swap юнитов из fstab, что экономит ещё немного времени. Для свопа — файл(ов) или раздел(ов), нужно создать *.swap юнит(ы) по тому-же пути что и маунты. На самом деле руками созавать файлы не нужно. Автосгенерённые юниты живут по пути /run/systemd/generator их просто нужно скопировать в каталог который я указал и поправить по вкусу. Для автомаунта разделов делаем такой финт: В тот-же каталог кладём одноимённый с маунтом *.automount и вообщем-то всё. Вот пример моего автомаунта раздела с /boot:
                              /etc/systemd/system/boot.mount:
                              [Unit]
                              Description=Boot partition (running by automount) /dev/sda1
                              Documentation=man:systemd.mount(5)
                              After=blockdev@dev-disk-by\x2duuid-ea65285a\x2d01da\x2d451c\x2da93a\x2d4b155c46aeeb.target

                              [Mount]
                              Where=/boot
                              What=/dev/disk/by-uuid/ea65285a-01da-451c-a93a-4b155c46aeeb
                              Type=ext4
                              Options=rw,relatime
                              DirectoryMode=0755

                              И парный, к нему автомаунт.
                              /etc/systemd/system/boot.automount:
                              [Unit]
                              Description=Automount boot partition when needed.

                              [Automount]
                              Where=/boot
                              ## Time to automatic umount of inactivity
                              TimeoutIdleSec=120

                              [Install]
                              WantedBy=multi-user.target
                          0
                          А кто-нибудь может рассказать как правильно делать в такой ситуации:
                          На сервер нужно скопировать файл, например в каталог /data
                          К серверу подключаемся под пользовательской учеткой с правами sudo, но у пользователя нет прав на запись в этот каталог.
                          Можно ли сразу через scp скопировать файл в конечный каталог без использования последующих команд вида
                          sudo mv ~/file /data/
                          или изменений разрешений в каталоге?
                            –1
                            нужно сперва подключиться пользователем и выполнить sudo chmod /data
                            а уже потом копировать файл
                              0

                              Можно, если использовать rsync и ему передать параметр --rsync-path "sudo rsync". Тогда на удаленной стороне будет запущено от рута

                                0
                                Спасибо, прочитал про rsync и вспомнил, что год назад уже гуглил этот вопрос и находил это решение, но все забыл.
                              0

                              Использовал sshfs для быстрого обновления исполняемых файлов на железе по make install

                                0

                                А ещё можно принимать и передавать файлы без дополнительных подключений, но для этого нужно, чтобы на клиенте работал Xorg (обычно так и есть). Сначала подключаемся к серверу с помощью ssh login@address -Y, можно проверить, что проброс подключения к Xorg работает через echo $DISPLAY, должно выдать что-то типа localhost:10.0. Если не выдало, проверьте /etc/ssh/sshd_config на сервере на предмет опций X11Forwarding yes и X11DisplayOffset 10.


                                Далее, ставим на этот сервер, к которому подключились, и себе на клиентскую машину пакет xclip. Всё, теперь можно выполнять xclip-copyfile /path/to/file1 /path/to/file2 ..., после чего в локальном уже терминале делать xclip-pastefile, файлы передадутся. Это работает, разумеется, в обе стороны. Никаких монтирований и прочего, всё по одному и тому же подключению. Использую этот способ уже очень давно, всё устраивает.

                                  –3

                                  Это все конечно хорошо, но как по мне ничего лучше mRemoteNg (к сожалению только на windows), в качестве обертки над cli утилитами доступа по различных протоколам не придумали. Очень хочу, чтобы его портировали под линукс...

                                    0

                                    В mc (midnight commander) открываешь правую или левую панель — и там выбираешь Shell-соединение. В качестве адреса — то же, что пишешь при коннекте по ssh (у меня обычно в ~/.ssh/config прописаны алиасы, чтоб одним словом переходить на любой рабочий сервер, если нужно с промежуточными джампами и авторизациями). Всё! Можно копировать туда/сюда; можно просматривать и редактировать файлы. И да, именно Shell (а не sftp). Работа последнего подразумевает, что на удалённом хосте есть служба sftp, а shell этого не нужно, достаточно просто возможности залогиниться.

                                      0
                                      mc жеж
                                        0
                                        локальный vim использую для открытия удаленных файлов
                                        vim scp://root@remote.host.com//etc/ssh/sshd_config


                                        им же, вимом можно и навигировать по удаленной файловой системе
                                          0

                                          Плюс sshfs в том, что он поднимается достаточно просто и имеет минимальнып настройки.
                                          На этом плюсы заканчиваются.


                                          Для обновления пары-тройки файлов или локального монтирования содержимого докера — вполне удобно.


                                          Проблемы начинаются, когда нужно прочитать/обновить каталоги от 5к файлов или со сложной древовидной структурой или залить от сотни мелких файлов.
                                          Или частые конкурентные чтения файлов из монтированного каталога.
                                          Здесь fuse существенно проигрывает по скорости тому же nfs и даже самбе.

                                            0

                                            "или за NAT-маршрутизатором, то есть, не имея постоянного IP-адреса.". — тема не раскрыта. Обычно сервер на работе может иметь доступ к интернету и нет белого или даже динамического ip. Также домашний компьютер максимум может иметь динамический ip, а скорее как и рабочий сервер имеет только доступ в инет. В таком сценарии только тимвьювер или гуглремоутдесктоп

                                            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                            Самое читаемое