Как расширить дисковое пространство на VPS за счет дисков на сервере в домашней сети

493c3ec15ef7c7696cf5e8da98ea3ebf

В настоящее время очень широкое распространение получили решения, основанные на self-hosting’e. При этом, под этим термином понимается идеология и практика, предусматривающая размещение веб-сервисов на собственных серверах, например домашних, вместо использования стороннего хостинга, как коммерческого, так и бесплатного.

Преимущества такого решения очевидны: это во первых полный контроль над данными, во вторых возможность организовать работу на той операционной системе и в той среде к которой вы привыкли, а в третьих на том железе, которое вам доступно и которое подчас намного мощнее того, что предлагает сторонний хостинг.

Но недостатки такого подхода тоже есть, и часто основной недостаток в том, что для предоставления доступа к вашим сетевым ресурсам вы должны обеспечить ряд условий: работающий сервер, статический IP, правильная настройка NAT в части маршрутизации пакетов и обеспечения безопасности. И если с первым вопросом более-менее ситуация решаемая, то остальные вопросы подчас становятся нерешаемыми в силу ряда причин, начиная от особенностей провайдеров, заканчивая тем сетевым железом, которое есть в распоряжении пользователя. Хорошо, если это будет какое то решение, основанное на RouterOS или OpenWRT, которое еще надо уметь настроить, что подчас совсем не просто. Но это может быть и какой то роутер начального уровня (или, что еще хуже провайдерское оборудование), которое крайне ограничено в своем функционале, на котором настроен свой NAT, которое может находится за NAT провайдера с «серым» IP. Поэтому популярные решения для self-hosted ресурсов вроде NextCloud становятся не такими уж и популярными как бы того хотелось.

Поэтому подчас без внешнего хостинга не обойтись. Например сделать это на VPS. И это хорошее и дешевое решение, если вам надо разместить собственные ресурсы, не требовательные к большому объему хранимых данных: собственный web-сервер с простыми страничками, VPN сервер, свой почтовый сервер, сервер для мессенджера или видеоконференций. Но дисковое пространство стоит дорого, и если стандартной VPS c 10–15GB дискового пространства вам не хватает, а вам надо разместить видеотеку или фотоальбом с размером 5–6TB, то покупка такого объема дискового пространства может влететь вам в копеечку.

Возникает вопрос:, а можно ли совместить оба решения, то есть реализовать self-hosted ресурсы на VPS, но при этом для дисковой памяти использовать то оборудование, которое у нас уже имеется в домашней сети, и с учетом всех тех ограничений на подключение извне, о которых было упомянуто? Да, можно, путем настройки VPN туннеля между серверами, это первое решение, которое приходит в голову. А можно ли это реализовать такую задачу как то проще?

Оказывается да, это возможно сделать буквально штатными средствами Linux, на которых хотел бы подробно остановится. К сожалению, в сети я не находил полною инструкцию, ем более для только русскоговорящих, поэтому давно сделал её для себя, которой хотел бы поделиться. Прошу простить некоторую занудность описания, которую могут отметить продвинутые в вопросе читатели, но моя цель не просто дать готовую инструкцию: «сделай так и все сразу заработает», а дать, в том числе, общее понимание того, что мы делаем. Потому что нет ничего хуже чем слепое повторение чьей то инструкции, и если что-то пойдет не так, то пользователь должен понимать как можно повлиять на ситуацию.

Сразу должен предупредить, что реализация подобной задачи описываемыми мной методами не является промышленным решением для высоконагруженных серверов. Очень многое зависит от ТТХ ваших серверов, каналов связи и их загрузки. Но в моем случае практика показала, что дешевая «одноядерная» VPS c 1Gb ROM и каналом на 100Mbit за 5Eur в месяц вполне способна обеспечить стриминг видеофайла с ваших домашних дисков с битрейтом 12–15Mbit/s, что нормально для FullHD 60fps с хорошим звуком. И это не предел. В случае же трансляции фото или музыки тут вообще нет преград (в разумных пределах, конечно).
Итак, входные условия, что мы имеем: домашний Ubuntu-server с дисковым массивом, VPS на Ubuntu-server, ssh доступ из сети в которой находится домашний сервер на VPS с правами root, относительно прямые руки и понимание некоторых аспектов работы сети. Поехали!

Наша первая задача — создание туннеля между удаленным сервером (далее просто «сервер») и домашним сервером за NAT (далее «клиент») внутри которого мы будем поднимать сетевые подключения и пускать полезный трафик. Хотя мы и хотим, чтобы сервер пользовался ресурсами клиента, и по необходимости подключался к его дискам, сделать мы это просто так в силу ранее заявленных условий не можем. Поэтому единственным возможным вариантом является инициализация открытия туннеля со стороны клиента. Почему бы и нет? Туннель между клиентом и сервером это двухсторонняя полоса движения, и как клиент может внутри туннеля использовать ресурсы сервера, так и сервер может получать ресурсы, которые мы согласны предоставить. Именно так работают все VPN, мы же будем использовать подобное соединение, но без VPN.

Итак, консоли нашего клиента вводим следующую команду:

ssh -fNT -R 9999:localhost:22 user@remoteserver.com

где user — это ваш логин для входа на ваш сервер, а remoteserver.com это доменное имя вашего удаленного сервера на VPS. Если доменное имя не используется, то на этом месте просто пишем IP вашей VPS. Если для входа на VPS через SSH вы используете не логин с паролем, а ключ, то команда будет выглядеть вот так:

ssh -i /home/user/keystore/private.pem -fNT -R 9999:localhost:22 user@remoteserver.com

где /home/user/keystore/private.pem путь к файлу ключа в каталоге пользователя. После ввода команды и пароля должно установиться ssh соединение с варим сервером. Для проверки правильности установки соединения можно ввести в консоли команду

ps aux | grep ssh

и на выводе получить нечто вроде этого:

user 13544 0.0 0.0 14900 2648? Ss 17:50 0:00 ssh -i /home/user/keystore/private.pem -fNT -R 9999: localhost:22 user@remoteserver.com

Все, туннель установлен и может дальше использоваться по назначению.

Давайте поймем что мы тут сделали.

Само по себе установление ssh соединения с сервером никакой магии не несет, это самая банальная вещь в мире. Но при обычном соединении мы лишь устанавливаем «одностороннее» движение, т. е. даем команды от клиента к серверу, сервер их выполняет и отдает клиенту только результат их выполнения. Но с ключом -R 9999: localhost:22 мы устанавливаем так называемый Remote Port Forwarding, т. е. перенаправление удаленного порта. Т.е. мы разрешаем серверу устанавливать соединение и обращаться к 22 порту нашего клиента, при этом на стороне сервера это будет происходить через обращение к порту 9999 localhost’a.

Вообще, порт, который мы назначаем для использования на сервере не обязательно 9999, теоретически он может быть любым. Самое главное, чтобы он бы уже не занят каким то процессом на сервере, иначе после установления соединения мы получим сообщение на клиенте «Warning: remote port forwarding failed for listen port …», это как раз и означает что на стороне сервера порт уже занят. Чтобы проверить свободные порты, достаточно на сервере дать команду

sudo netstat -ntlp

мы увидим уже занятые порты. Желательно также, чтобы порт для использования на сервере не попадал в диапазон »0–1024», т. к. этот диапазон выделен под порты, которые выполняются процессами под root, и при назначении таких портов мы можем получить также уведомление об ошибке.

Ключ -fNT означает, что ssh соединение будет работать как фоновый процесс, т. е. оно на стороне клиента не будет запрашивать и ждать получения команд и сервер также не будет ждать дальнейших команд от клиента. Проверить же успешность установления соединения на сервере можно также командой

sudo netstat -ntlp | grep ssh

Если ввести её на сервере после инициирования соединения со стороны клиента, то мы увидим что-то вроде

tcp 0 0 127.0.0.1:9999 0.0.0.0:* LISTEN 27004/sshd: user

Это означает, что наш клиент соединен с сервером и на сервере открыт порт 9999 для обращения через него к ресурсам клиента.

Итак, после успешного открытия туннеля теперь стоит вторая задача: воспользоваться им для обращения со стороны сервера к диску на клиенте. Для решения этой задачи воспользуемся sshfs — приложением «клиент-сервер» для удаленного управления файлами по протоколу ssh.

Преимуществ у sshfs два: во первых она работает через порт 22, уже открытый для работы по ssh и уже установленный нами для прослушивания на клиенте (помните, -R 9999: localhost:22? — так вот 22 там стоит неспроста, как раз для этого) и во вторых позволяет монтировать удаленные каталоги как локальный том. Т.е. на сервере мы можем обращаться просто к каталогу /mnt/clientfolder и видеть файлы клиента таким образом, как будто они находятся на самом сервере. Сначала проверяем, есть ли данная программа на сервере и клиенте: даем команду

sshfs -- version

если получили значение версии — то отлично, все будет работать, если нет, то установим программу через

sudo apt update && sudo apt install sshfs

Теперь на сервере необходимо создать каталог, куда мы будем монтировать каталог клиента

sudo mkdir /mnt/clientfolder

Дадим каталогу права локального пользователя сервера

sudo chown -R user:user /mnt/clientfolder/

где user — имя пользователя и его группы, под которым вы работаете на сервере.

Приготовления закончены, теперь даем команду на подключение каталога клиента. Допустим, мы хотим видеть на сервере в каталоге /mnt/clientfolder содержимое каталога клиента /home/user/Video, тогда команда, которая дается сервере будет иметь вид:

sudo sshfs -p 9999 -o idmap=user,nonempty user@127.0.0.1:/home/user/Video /mnt/clientfolder

Давайте разберемся, что тут написано.

-p 9999 — означает, что соединение sshfs, которое мы инициируем, должно проводится с использованием порта 9999, который мы открыли для туннеля с клиентом

idmap=user, nonempty — опция, необходимая для ассоциации локального пользователя и пользователя на сервере (будет работать и без нее, но необходимо для правильного установления владельцев и прав на создаваемые удаленно файлы).

user@127.0.0.1:/home/user/Video — каталог клиента, содержимое которого мы хотим видеть на сервере, тут необходимо «user» заменить на имя того пользователя, от имени которого мы устанавливали туннель на клиенте

/mnt/clientfolder — каталог сервера, куда будет монтироваться каталог клиента

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

ls -al /mnt/clientfolder/

Вы увидите, что наш сервер находящийся на VPS получил доступ к файлам, находящимся на вашем домашнем сервере. Теперь с этим каталогом можно делать что душе угодно, дать ему доступ к web-серверу например, хранить в данном файле бэкапы вашей SQL базы данных и так далее.

Если необходимость в смонтированном каталоге пропала, и вы решили его размонтировать, то на сервере необходимо выполнить команду

fusermount -u /mnt/clientfolder

Если необходимо полностью закрыть туннель, то на клиенте достаточно дать команду

ps aux | grep ssh

посмотреть идентификатор процесса, который отвечает за соответствующее соединение (допустим 1111) и дать команду

kill 1111

При монтировании удаленного каталога через sshfs с помощью вышеприведенной команды следует учитывать один нюанс. Поскольку мы монтируем каталог от локального пользователя сервера, то и права на файлы в смонтированном каталоге тоже принадлежат этому пользователю. Иногда это является проблемой, например, если вы хотите дать доступ к просмотру ваших файлов через web, пишете какой то код на PHP к примеру, который должен обращаться к вашим файлам, тогда будут возникать трудности с доступом, поскольку web сервер оперирует от имени пользователя и группы www-data: www-data.

Чтобы обойти это ограничение, надо в команде монтирования использовать ключ allow_other и команда на сервере будет выглядеть следующим образом:

sshfs -p 9999 -o idmap=user,nonempty,allow_other user@127.0.0.1:/home/user/Video /mnt/clientfolder

Не забудьте включить разрешение на использование этого ключа на сервере в конфиге /etc/fuse.conf расскоментив опцию user_allow_other

Особо надо отметить, что при этом мы даем доступ к файлам web серверу, и тем приложениям, которые на нем работают, если они при этом имеют доступ к монтируемому каталогу. Поэтому вопросы безопасности файлов и доступа к ним также ложатся на управление web приложением. Не следует в этом случае давать доступ всем клиентам вашего web-сервера к файлам без авторизации.

Иногда, по какой то причине нет желания или возможности использовать sshfs, и целесообразно использовать вместо него уже настроенный на домашней машине Samba сервер. Можно ли провернуть подобную махинацию с Samba? Нет ничего проще!

По уже известной нам аналогии даем на клиентской машине команду на установление туннеля:

ssh -i /home/user/keystore/private.pem -fNT -R 9999:localhost:445 user@remoteserver.com

Разница лишь в том, что мы заменили порт, к которому идет обращение на стороне клиента с 22 (на котором работает sshfs) на 445 (на котором работает Samba). На стороне сервера команда выглядит немного иначе:

sudo mount -t cifs -o username=sambauser,port=9999 //127.0.0.1/sambashare /mnt/clientfolder/

обратите внимание, что тут команда дается с sudo, при этом подразумевается, что cifs клиент на сервере у вас также установлен, если нет, то его тоже надо установить, иначе получим сообщение об ошибке.

Тут надо пояснить следующие моменты. Поскольку Samba использует свою систему авторизации и свои каталоги для монтирования и доступа к данным, то в команде имя sambauser — надо заменить на имя того пользователя, которым вы регистрируетесь, когда входите на диски, расшаренные Samba (а не тот Linux пользователь, который устанавливает туннель) и sambashare заменить на тот путь, который предоставляет Samba для пользователей. То есть, если в локальной сети вы заходите в расшаренный диск по адресу 192.168.1.1/sambashare, то его и надо вводить, а путь к каталогу в Linux, который вы ходите расшарить.

Если вы не устанавливали пароль для Samba каталогов, а заходите анонимно, то команда будет sudo mount -t cifs -o port=9999,password='' //127.0.0.1/sambashare /mnt/clientfolder/

(пароль просто две одинарные кавычки без пробела).

Если вы столкнулись с проблемой предоставления доступа через web сервер, аналогичной той, о которой было написано выше для sshfs папок, то можно решить её командой

sudo mount -t cifs -o port=9999,password='',file_mode=0777,dir_mode=0777 //127.0.0.1/sambashare /mnt/clientfolder/

file_mode=0777, dir_mode=0777 — в данном случае дает пользователем доступ на чтение и запись каталогов и файлов смонтированного каталога.

При этом все вопросы безопасности файлов и доступа к ним также ложатся на управление доступом web приложением, если оно имеет доступ к монтируемому каталогу.

Размонтирование каталога производится командой

sudo umount /mnt/clientfolde

Вот, собственно и все, чем хотел поделиться. Надеюсь, что данная статья поможет кому то в организации работы. Спасибо что прочитали. Всем удачи!

© Habrahabr.ru