Storage VPS как сетевой диск: rclone, SSHFS и WebDAV
Подключаем storage VPS как диск в Explorer, Finder или файловом менеджере Linux: rclone mount, SSHFS и WebDAV, chroot для SFTP, шифрование rclone crypt и обрывы связи на ноутбуке.
Что вы получите
Storage VPS как сетевой диск: каталог на вашем сервере виден в «Проводнике» Windows, в Finder или в файловом менеджере Linux как обычная папка, в которую можно перетащить файл. Способов три: rclone mount (работает на всех трёх ОС), SSHFS (Linux и macOS) и WebDAV, который операционная система подключает сама, без сторонних программ. На сервере для этого нужен либо один SSH-пользователь, запертый в своём каталоге через chroot, либо один vhost nginx с TLS. Ниже обе серверные схемы и все три клиентские.
Сразу о границах. Сетевой диск через интернет с задержкой 40-80 мс подходит для архива, документов, фото, видео и бэкапов, то есть для файлов, которые читают целиком. Он не подходит для базы данных, каталога Lightroom, библиотеки Apple Photos и всего, что читает файл мелкими кусками в случайных местах. Для таких данных нужна синхронизация, а не монтирование, и этому посвящён отдельный раздел. Сам сервер здесь считается уже купленным: если вы ещё выбираете, разница между storage VPS и обычным VPS сводится к цене терабайта и к скорости диска, и для сетевого диска важна именно цена.
Чем storage VPS как сетевой диск отличается от Яндекс Диска
Большинство читателей приходят сюда с подписки: Яндекс 360, Облако Mail.ru, Google One или iCloud. Там есть готовый клиент, веб-галерея и квота, привязанная к одному аккаунту. Storage VPS даёт другое.
- Данные лежат на диске, который арендовали вы, а не в сервисе, который читает файлы по своим правилам, может ограничить аккаунт и переписать тариф. С
rclone crypt(раздел ниже) хостер тоже видит только шифротекст. - Один сервер обслуживает всю семью или небольшую команду: каждому свой SSH-пользователь или свой логин WebDAV, без отдельной подписки на человека.
- Объём считается терабайтами, а не ступеньками тарифа. Сколько брать, лучше прикинуть заранее по расчёту нужного объёма storage VPS, потому что цена терабайта падает с ростом плана.
- Нет клиента с индексацией, автозагрузкой с телефона и совместным редактированием. Если это нужно, смотрите на Nextcloud, а не на сетевой диск.
Если вы когда-нибудь подключали Яндекс Диск через webdav.yandex.ru, то вариант с WebDAV ниже устроен точно так же. Меняется только адрес сервера, и он теперь ваш. Скорость до сервера и правовые вопросы для пользователей из России разобраны в отдельном материале про storage VPS для России, здесь я их не повторяю.
Сервер: SFTP-пользователь в chroot
Одна серверная схема закрывает два клиентских способа: и rclone mount, и SSHFS ходят по SFTP. Нужен отдельный пользователь без шелла, который видит только свой каталог. OpenSSH делает это встроенными средствами, ставить ничего не надо.
sudo adduser --disabled-password --gecos "" drive
sudo install -d -m 755 -o root -g root /srv/drive
sudo install -d -m 750 -o drive -g drive /srv/drive/data
sudo install -d -m 700 -o drive -g drive /home/drive/.ssh
echo 'ssh-ed25519 AAAA...ваш публичный ключ... laptop' | sudo tee /home/drive/.ssh/authorized_keys
sudo chown drive:drive /home/drive/.ssh/authorized_keys
sudo chmod 600 /home/drive/.ssh/authorized_keysДва каталога нужны из-за правила OpenSSH: корень chroot обязан принадлежать root и не может быть доступен на запись никому другому. Поэтому /srv/drive принадлежит root, а писать пользователь может только в /srv/drive/data. Если сделать корень доступным на запись, сервер разорвёт соединение сразу после аутентификации, а в journalctl -u ssh появится строка fatal: bad ownership or modes for chroot directory "/srv/drive".
Теперь блок Match в конце /etc/ssh/sshd_config. Именно в конце: всё, что написано после Match, относится только к нему.
sudo tee -a /etc/ssh/sshd_config >/dev/null <<'EOF'
Match User drive
ChrootDirectory /srv/drive
ForceCommand internal-sftp
AllowTcpForwarding no
X11Forwarding no
PasswordAuthentication no
EOF
sudo sshd -t && sudo systemctl reload sshsshd -t молча завершается при правильном конфиге и печатает имя файла с номером строки при ошибке. Проверьте с ноутбука:
ssh drive@203.0.113.10
sftp drive@203.0.113.10Первая команда должна ответить This service allows sftp connections only. и закрыть соединение: это ForceCommand internal-sftp отказывает в шелле. Вторая должна открыть приглашение sftp>, где ls показывает единственный каталог data, а pwd печатает /. Корень, который видит пользователь, это /srv/drive на сервере, поэтому во всех клиентских командах ниже путь к данным пишется как /data.
Начальную заливку большого архива через смонтированный диск делать не стоит: это самый медленный из возможных путей. Быстрее перелить каталог по SSH одним потоком tar тем же пользователем или запустить rclone copy с несколькими потоками, а диск подключать уже к готовым данным.
Сервер, вариант 2: WebDAV за TLS в nginx
WebDAV нужен, когда на клиент нельзя ничего поставить: рабочий ноутбук с политиками, планшет, телевизор с медиаплеером, файловый менеджер на Android. Протокол это HTTP с дополнительными методами (PROPFIND для списка каталога, PUT для загрузки, MKCOL для создания папки, LOCK для блокировок), так что сервером служит обычный nginx с модулем dav_ext и сертификатом Let's Encrypt. Домен должен уже указывать на VPS.
sudo apt update
sudo apt install -y nginx libnginx-mod-http-dav-ext apache2-utils certbot python3-certbot-nginx
sudo certbot certonly --nginx -d drive.example.com
sudo install -d -m 750 -o www-data -g www-data /srv/dav
sudo htpasswd -c /etc/nginx/dav.htpasswd anna
echo 'dav_ext_lock_zone zone=dav:10m;' | sudo tee /etc/nginx/conf.d/dav-lock.confФайл /etc/nginx/sites-available/drive:
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name drive.example.com;
ssl_certificate /etc/letsencrypt/live/drive.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/drive.example.com/privkey.pem;
client_max_body_size 0;
location / {
root /srv/dav;
auth_basic "drive";
auth_basic_user_file /etc/nginx/dav.htpasswd;
set $x $uri$request_method;
if ($x ~ [^/]MKCOL$) {
rewrite ^(.*)$ $1/;
}
dav_methods PUT DELETE MKCOL COPY MOVE;
dav_ext_methods PROPFIND OPTIONS LOCK UNLOCK;
dav_ext_lock zone=dav;
dav_access user:rw group:rw all:r;
create_full_put_path on;
autoindex on;
}
}client_max_body_size 0 снимает лимит nginx в 1 МБ на тело запроса, иначе любой файл крупнее вернёт 413 Request Entity Too Large. Блок с MKCOL нужен потому, что nginx принимает MKCOL только с косой чертой на конце, а Finder и «Проводник» её не ставят: без переписывания создание папки отвечает 409 Conflict. LOCK и UNLOCK нужны Finder: без них он монтирует том только для чтения. Каталог /srv/dav принадлежит www-data, и это отдельный каталог, а не /srv/drive/data: файлы, созданные через SFTP, принадлежат drive, и nginx не сможет их перезаписать.
sudo ln -s /etc/nginx/sites-available/drive /etc/nginx/sites-enabled/drive
sudo nginx -t && sudo systemctl reload nginx
curl -u anna -X PROPFIND -H 'Depth: 1' https://drive.example.com/curl спросит пароль и должен вернуть XML, который начинается с <D:multistatus. Ответ 401 означает ошибку в htpasswd. Ответ 405 Not Allowed означает, что модуль dav_ext не загружен: пакет должен был создать /etc/nginx/modules-enabled/50-mod-http-dav-ext.conf, проверьте, что файл на месте.
Способ 1: rclone mount на Windows, macOS и Linux
rclone один и тот же на всех трёх ОС, поэтому конфиг с ноутбука на Linux можно скопировать на Windows. Ему нужен драйвер FUSE (filesystem in userspace, файловая система в пространстве пользователя): WinFsp на Windows, macFUSE на macOS (есть и вариант без расширения ядра, FUSE-T), а на Linux он уже в ядре.
# Linux
sudo -v ; curl https://rclone.org/install.sh | sudo bash
# macOS
brew install rclone
brew install --cask macfuse# Windows
winget install WinFsp.WinFsp
winget install Rclone.RcloneОдна команда создаёт remote (так rclone называет описание подключения). После первого ssh drive@... ключ сервера уже лежит в ~/.ssh/known_hosts, и его стоит включить в проверку:
rclone config create storage sftp host=203.0.113.10 user=drive \
key_file=~/.ssh/id_ed25519 known_hosts_file=~/.ssh/known_hosts shell_type=none
rclone lsd storage:/shell_type=none обязателен для chroot-пользователя: без него rclone пытается выполнить команду в шелле, чтобы определить его тип, а internal-sftp шелла не даёт. lsd должен напечатать строку с data. Дальше монтирование:
mkdir -p ~/drive
rclone mount storage:/data ~/drive --vfs-cache-mode full --vfs-cache-max-size 10G --dir-cache-time 1mrclone mount storage:/data X: --vfs-cache-mode full --vfs-cache-max-size 10G --network-modeКоманда не возвращает управление, пока диск смонтирован: это нормально, откройте второе окно терминала. --network-mode показывает букву как сетевой диск в «Проводнике», а не как локальный. --vfs-cache-mode full здесь главный флаг. Без него rclone отдаёт файл приложению напрямую с сервера, и любая программа, которая пишет не последовательно (офисные пакеты, архиваторы), получает ошибку. С ним всё открытое лежит в локальном кеше на диске ноутбука, приложение работает с локальной копией, а rclone выгружает изменения в фоне. --vfs-cache-max-size 10G ограничивает этот кеш. --dir-cache-time 1m определяет, через сколько вы увидите файл, положенный на сервер с другого устройства; по умолчанию это пять минут.
На Linux удобно оформить это как пользовательский unit systemd, файл ~/.config/systemd/user/rclone-drive.service:
[Unit]
Description=Storage VPS as a drive
[Service]
Type=notify
ExecStart=/usr/bin/rclone mount storage:/data %h/drive \
--config %h/.config/rclone/rclone.conf \
--cache-dir %h/.cache/rclone \
--vfs-cache-mode full --vfs-cache-max-size 10G --dir-cache-time 1m
ExecStop=/bin/fusermount -uz %h/drive
Restart=on-failure
RestartSec=10
[Install]
WantedBy=default.targetsystemctl --user daemon-reload
systemctl --user enable --now rclone-drive.service
systemctl --user status rclone-drive.serviceType=notify означает, что unit считается запущенным только после того, как rclone реально смонтировал каталог, поэтому active (running) в выводе status подтверждает рабочий диск, а не просто живой процесс. Пути через %h (домашний каталог) и явный --config нужны потому, что systemd не гарантирует переменным окружения тех значений, к которым вы привыкли в терминале. На Windows ту же команду rclone mount ставят в «Планировщик заданий» с запуском при входе в систему, на macOS в launchd.
Способ 2: SSHFS на Linux и macOS
SSHFS это FUSE-драйвер, который превращает SFTP-сессию в каталог. Кеша у него нет, каждая операция уходит на сервер, поэтому он проще rclone и заметно медленнее на мелких файлах. Зато на Linux это одна команда.
sudo apt install -y sshfs
mkdir -p ~/drive
sshfs drive@203.0.113.10:/data ~/drive -o reconnect,ServerAliveInterval=15,ServerAliveCountMax=3,idmap=user
ls ~/drive
fusermount -u ~/driveServerAliveInterval=15 вместе с ServerAliveCountMax=3 заставляет SSH заметить пропавшую сеть за 45 секунд, а reconnect после этого поднимает сессию заново. Без этих опций SSHFS висит на мёртвом TCP-соединении, пока ядро само не сдастся, а это больше десяти минут. idmap=user показывает файлы удалённого пользователя drive как ваши, иначе ls -l печатает чужой числовой uid.
На macOS SSHFS ушёл из основного репозитория Homebrew, потому что зависит от macFUSE с расширением ядра. Он живёт в стороннем tap:
brew install --cask macfuse
brew install gromgit/fuse/sshfs-macmacFUSE после установки требует разрешить расширение в «Системных настройках», а на Apple Silicon ещё и снизить политику безопасности в режиме восстановления. Если это лишний шаг, rclone mount на macOS проще.
Чтобы диск на Linux поднимался при первом обращении и сам отпускался в простое, опишите его в /etc/fstab через автомонтирование systemd. Подставьте свой домашний каталог и свой uid из id -u; строка одна, переносов в fstab нет:
drive@203.0.113.10:/data /home/anna/drive fuse.sshfs noauto,x-systemd.automount,x-systemd.idle-timeout=10min,_netdev,allow_other,uid=1000,gid=1000,IdentityFile=/home/anna/.ssh/id_ed25519,UserKnownHostsFile=/home/anna/.ssh/known_hosts,reconnect,ServerAliveInterval=15,ServerAliveCountMax=3 0 0sudo systemctl daemon-reload
ls ~/driveМонтирует здесь systemd от имени root, отсюда явные IdentityFile и UserKnownHostsFile: у root свой ~/.ssh, и без этих опций он не найдёт ни ключа, ни отпечатка сервера, а journalctl -u home-anna-drive.mount покажет Host key verification failed или Permission denied (publickey). allow_other вместе с uid= и gid= нужны по той же причине: к тому, что смонтировал root, обычный пользователь без них доступа не имеет. x-systemd.idle-timeout=10min отпускает диск через десять минут без обращений. Для ноутбука это лучшая из опций: он чаще всего засыпает уже без монтирования и просто поднимает его заново при следующем ls.
Способ 3: WebDAV средствами самой ОС
Ничего ставить не нужно, сервер из раздела про nginx уже готов.
- Windows: «Проводник», «Этот компьютер», «Подключить сетевой диск», в поле папки
https://drive.example.com/. Из командной строки:net use W: https://drive.example.com/ /user:anna /persistent:yes. - macOS: Finder, меню «Переход», «Подключение к серверу» (Cmd+K), адрес
https://drive.example.com/. - GNOME: в «Файлах» откройте «Другие места», адрес
davs://drive.example.com/. KDE Dolphin:webdavs://drive.example.com/. - Linux без графики:
sudo apt install -y davfs2, затемsudo mkdir -p /mnt/driveиsudo mount -t davfs https://drive.example.com/ /mnt/drive.
Встроенный клиент Windows самый капризный из трёх. Он ходит через службу WebClient, почти при каждом открытии папки заново запрашивает PROPFIND, а файлы крупнее 50 МБ отвергает с ошибкой 0x800700DF: The file size exceeds the limit allowed and cannot be saved. Лимит задаёт параметр реестра FileSizeLimitInBytes в HKLM\SYSTEM\CurrentControlSet\Services\WebClient\Parameters, максимум 4294967295, то есть 4 ГБ; крупнее через этот клиент не пройдёт вовсе. Для видеоархива это делает WebDAV на Windows непригодным, берите rclone. Finder ведёт себя лучше, но при каждом просмотре создаёт на сервере файлы ._имя и .DS_Store, их видно в ls на VPS.
Шифрование rclone crypt: хостер видит только шифротекст
Диск физически стоит у хостера, и у него есть root. Если это неприемлемо, поверх storage создаётся второй remote типа crypt: rclone шифрует имена и содержимое файлов на ноутбуке и кладёт на сервер уже шифротекст. Ключ на сервер не попадает.
rclone config create secret crypt remote=storage:/data/enc \
filename_encryption=standard directory_name_encryption=true \
password='длинная фраза' password2='вторая фраза для соли' --obscure
rclone mkdir secret:
rclone touch secret:hello.txt
rclone ls secret:
rclone ls storage:/data/encls secret: печатает hello.txt, а ls storage:/data/enc печатает тот же файл под именем вроде k5a3n6q2vbo7hj4dp2lqe6ri3c и на 32 байта длиннее: это заголовок с nonce, и ещё по 16 байт добавляется на каждые 64 КиБ данных. Хостер видит число файлов, их размеры с точностью до этих байтов, даты изменения и структуру каталогов, но не имена и не содержимое. Дальше везде вместо storage:/data подставляйте secret:, и rclone mount secret: ~/drive ... даёт тот же диск, только зашифрованный.
Важно: rclone.conf теперь единственное место, где лежит ключ. Потеряете файл и не запишете фразу, и данные не вернуть ничем. Команда rclone config file печатает путь к нему; положите копию в менеджер паролей. Если хочется понять, где шифровать правильнее, на клиенте или на самом сервере, разбор способов шифрования данных на storage VPS сравнивает эти варианты.
Почему база данных и каталог фотографий сюда не годятся
Сетевой диск делает вид, что удалённый файл локальный. Приложение этому верит и читает его так, как читало бы с SSD: по 4-8 КиБ, в случайных местах, десятки тысяч раз. Каждое такое чтение по SFTP или WebDAV это один запрос и один ответ, то есть один полный оборот до сервера и обратно (RTT, round-trip time). Дальше арифметика, а не бенчмарк: одно соединение успевает сделать не больше 1000 / RTT операций в секунду.
The data behind this chart
[
{
"label": "\u0414\u043e\u043c\u0430\u0448\u043d\u044f\u044f \u0441\u0435\u0442\u044c, 1 \u043c\u0441",
"rtt_ms": 1,
"ops_per_sec": 1000,
"seconds_for_25000_ops": 25
},
{
"label": "VPS \u0432 \u0441\u043e\u0441\u0435\u0434\u043d\u0435\u0439 \u0441\u0442\u0440\u0430\u043d\u0435, 40 \u043c\u0441",
"rtt_ms": 40,
"ops_per_sec": 25,
"seconds_for_25000_ops": 1000
},
{
"label": "\u0414\u0430\u043b\u044c\u043d\u0438\u0439 VPS, 80 \u043c\u0441",
"rtt_ms": 80,
"ops_per_sec": 12.5,
"seconds_for_25000_ops": 2000
}
]База SQLite на 100 МБ, прочитанная страницами по 4 КиБ, это около 25 000 запросов. В домашней сети они занимают 25 секунд, на VPS с задержкой 40 мс уже 1000 секунд, при 80 мс 2000, то есть больше получаса. Приложение при этом не показывает прогресс, оно просто «зависло». Кеш rclone меняет картину, но не решает задачу: при первом открытии каталога Lightroom на 2 ГБ rclone скачает почти весь файл, потом приложение работает быстро, а при закрытии rclone выгрузит все 2 ГБ обратно, потому что заливает изменённый файл целиком.
Вторая проблема глубже. SQLite, а с ним Lightroom, Apple Photos и половина настольных программ, опираются на блокировки байтовых диапазонов файла. SSHFS и rclone не передают их на сервер: блокировка существует только в ядре вашего ноутбука. Два устройства с одним каталогом думают, что каждое держит замок, и файл повреждается. Не случайно Lightroom отказывается открывать каталог на сетевом томе, а Photos не открывает библиотеку с него.
Для таких данных нужна синхронизация: полная локальная копия на каждом устройстве и обмен изменениями через сервер. Сравнение Syncthing и Nextcloud показывает, какой из двух инструментов брать, а storage VPS в этой схеме становится ещё одной копией с большим диском. И не путайте диск с бэкапом: файл, удалённый в «Проводнике», исчезает с VPS в ту же секунду, и storage VPS сам по себе бэкапом не является.
Что происходит с диском, когда ноутбук уснул
Во сне TCP-соединение с сервером умирает, и три способа переживают это по-разному.
- rclone закрывает простаивающие SFTP-соединения через минуту (
--sftp-idle-timeout 1mпо умолчанию), поэтому после долгого сна пула соединений нет вовсе, и первое обращение просто открывает новое. После короткого сна первое обращение может подвиснуть на несколько секунд, пока TCP не признает старое соединение мёртвым, потом rclone повторит запрос. Файлы, изменённые без сети, лежат в кеше и выгружаются, когда сеть вернётся: неудачная выгрузка повторяется с растущим интервалом, до одной минуты между попытками. Чтение того, чего в кеше нет, отдаёт приложению ошибку ввода-вывода. - SSHFS без
reconnectоставляет каталог с ошибкойTransport endpoint is not connectedна каждом обращении, и дажеls ~спотыкается об эту точку монтирования. Лечитсяfusermount -uz ~/drive(ленивое отмонтирование) и новымsshfs. СreconnectиServerAlive*это происходит само, а сx-systemd.automountиidle-timeoutдиск обычно отпускается ещё до сна. - WebDAV в Windows теряет букву после сна или смены сети.
/persistent:yesвозвращает её при следующем входе, до этого нужен повторныйnet useили двойной щелчок по диску. Finder показывает сообщение о прерванном соединении с сервером и предлагает отключить том.
Какой способ выбрать
rclone mount: вариант по умолчанию для всех. Единственный с локальным кешем и шифрованием, и он одинаково ведёт себя на трёх ОС.- SSHFS: Linux-ноутбук, ничего кроме
apt install, данные не секретны от хостера, файлы крупные. - WebDAV: клиент, на который нельзя ставить программы, или устройство без FUSE. Для файлов до нескольких десятков МБ на Windows, для любых на GNOME и KDE.
FAQ
Почему папка с тысячами файлов на сетевом диске открывается так долго?
Сам список каталога SFTP отдаёт пачками, это недорого. Дорого то, что файловый менеджер делает потом: «Проводник» открывает каждое изображение ради миниатюры, «Файлы» GNOME читают начало файлов, тип которых нельзя определить по имени. Каждое открытие это несколько оборотов до сервера по 40-80 мс, и тысяча файлов превращается в минуты. Отключите миниатюры для сетевых расположений (в «Проводнике» это пункт «Всегда отображать значки, а не эскизы», в настройках «Файлов» GNOME ограничьте миниатюры локальными файлами) или используйте rclone mount, у которого список каталога кешируется на время --dir-cache-time.
Можно ли держать на таком диске базу данных или каталог Lightroom?
Нет. База читается страницами по 4 КиБ в случайных местах, и при задержке 40 мс одно соединение успевает не больше 25 таких чтений в секунду. Кроме того, блокировки файла, на которые опираются SQLite, Lightroom и Apple Photos, через SSHFS и rclone на сервер не передаются, так что два устройства с одним каталогом повредят его. Держите каталог локально, а на VPS отправляйте его через Syncthing или Nextcloud.
Видит ли хостер мои файлы?
При обычном SFTP или WebDAV да: у хостера есть root на машине, где лежит диск. Remote типа crypt в rclone шифрует имена и содержимое на вашем ноутбуке, и на сервер попадает только шифротекст. Хостер по-прежнему видит число файлов, их размеры, даты изменения и структуру каталогов. Фраза-пароль хранится только в rclone.conf, и без неё данные не восстановить, поэтому скопируйте её в менеджер паролей сразу после rclone config create.
Диск показывает «Transport endpoint is not connected». Что делать?
Процесс SSHFS потерял SSH-сессию, а точка монтирования осталась. Выполните fusermount -uz ~/drive, чтобы отпустить её, и смонтируйте заново. Чтобы это не повторялось, монтируйте с -o reconnect,ServerAliveInterval=15,ServerAliveCountMax=3, а на ноутбуке ещё лучше описать диск в /etc/fstab с x-systemd.automount и x-systemd.idle-timeout=10min, тогда systemd сам отпустит диск в простое и поднимет при следующем обращении.
Нужно ли ставить на сервер что-то кроме OpenSSH?
Для rclone mount и SSHFS ничего: оба работают по SFTP, который OpenSSH уже умеет, нужен только пользователь с ChrootDirectory и ForceCommand internal-sftp. nginx с модулем dav_ext и сертификатом нужен только для WebDAV, то есть когда на клиенте нельзя установить rclone.