Если SFTP-клиент входит на сервер, показывает папки и скачивает файлы без возражений, но любое сохранение, загрузка или удаление заканчивается ошибкой Permission denied, дело не во входе. Аутентификация прошла. Не прошла следующая проверка: операционная система (или SFTP-служба панели) решает, может ли пользователь, под которым вы вошли, писать в этот конкретный файл или в папку, где он лежит. На машине, которую вы администрируете сами, причина почти всегда в владельце: файлы принадлежат пользователю службы или root, а вы вошли под кем-то другим. На игровой панели причина почти всегда в праве доступа в самой панели, в защищённом файле или в переполненном диске. Исправление - никогда не chmod 777.
В этой статье причины разобраны в том порядке, в каком они встречаются на практике, для каждой дана команда, которая её подтверждает, и исправление, не создающее новую проблему. Права на файлы и бит исполнения подробно описаны в статье права и владельцы файлов игрового сервера; здесь речь о конкретной ситуации, когда вы подключились и всё равно не можете писать.
Чтение работает, запись нет: почему#
SFTP - это не отдельная система прав. На обычном Linux-сервере sftp-server из OpenSSH (или internal-sftp) работает от имени пользователя, под которым вы вошли, и каждая файловая операция - обычный системный вызов от этого пользователя. Если alice не может записать файл из shell, она не сможет записать его и по SFTP. Клиент лишь сообщает то, что ответило ядро.
Для чтения нужно гораздо меньше, чем для записи. Чтобы скачать server.properties, нужен r на файл и x на каждую папку выше. Чтобы изменить его, нужен w на файл. Чтобы загрузить новый файл, удалить или переименовать существующий, нужны w и x на папку, независимо от режима самого файла. Из-за этой асимметрии жалоба "я всё вижу, но ничего не могу изменить" так распространена: права по умолчанию для файлов 644, для папок 755, и всем, кроме владельца, это даёт ровно это - читать, смотреть список, скачивать, и ничего больше.
Сначала убедитесь, что это ошибка записи, а не ошибка входа. Это разные проблемы:
Permission denied (publickey,password). <- login failed, see SSH keysError: /srv/game/server.properties: open for write: permission deniedremote open("/srv/game/start.sh"): Permission deniedCouldn't open for writingПервая строка означает, что вы вообще не вошли, и для неё есть статья SSH permission denied (publickey). Всё дальнейшее - про остальные три, которые значат одно и то же: вход выполнен, но на одном файле или одной папке отказ. Точная формулировка зависит от клиента: FileZilla пишет open for write: permission denied, консольный клиент sftp из OpenSSH - remote open(...) или dest open, а плагины редакторов обычно сообщают, что не удалось открыть файл для записи.
Кто владеет файлом и кто вы#
Почти любой случай проясняют две команды. По SSH или из приглашения sftp посмотрите на файл и его папку:
$ ls -la /srv/game/drwxr-xr-x 5 steam steam 4096 Oct 14 20:10 .-rw-r--r-- 1 steam steam 1843 Oct 14 20:11 server.properties-rw-r--r-- 1 root root 612 Oct 12 09:02 mods.json$ iduid=1001(alice) gid=1001(alice) groups=1001(alice)Прочитайте это как предложение. Папка принадлежит steam, и писать в неё может только steam. server.properties принадлежит steam, и менять его может только steam. mods.json принадлежит root, так что даже steam его изменить не может. А вы - alice, ни тот и ни другой, поэтому к вам относятся только последние три бита: r-x на папку и r-- на файлы. Только чтение, ровно как вы и наблюдали.
Графические клиенты показывают те же столбцы. В FileZilla на удалённой панели есть столбцы Permissions и Owner/Group; в WinSCP они на удалённой панели и в свойствах файла. Если в столбце владельца вместо имени стоит число (988, 1000), у клиента просто нет имени для этого id - владение от этого не исчезает.
В таблице ниже - что нужно для каждой операции. Обратите внимание, как часто папка важнее файла:
| Что вы хотите | На файле | На папке |
|---|---|---|
| Скачать | r | x (и r, чтобы увидеть список) |
| Изменить и сохранить на месте | w | x |
| Загрузить новый файл | - | w и x |
| Удалить или переименовать | ничего | w и x |
| Сохранить через временный файл | - | w и x |
Последняя строка - то, на чём спотыкаются с редакторами, поэтому ей посвящён отдельный раздел ниже.
Файлы, созданные службой или root#
На VDS или домашнем сервере история обычно такая. Игра, веб-приложение или бот работает от отдельного пользователя службы - steam, www-data, minecraft. Вы входите по SFTP под своим пользователем, чтобы поправить конфиг. Ваш пользователь может прочитать всё (файлы 644) и не может записать ничего. Или вы уже один раз это исправили, а оно вернулось, потому что служба продолжает создавать новые файлы со своим владельцем и umask 022. Или кто-то выполнил обновление через sudo, и теперь часть файлов принадлежит root, и даже служба не может их изменить.
Есть три разумных способа исправить это, и какой из них верен, зависит от того, кто должен владеть данными.
Войдите как пользователь службы. Самый простой вариант, когда сервером занимается один человек. Выдайте пользователю службы SSH-ключ (не пароль) и подключайтесь под ним. Всё, что вы загрузите, сразу получит правильного владельца. Для пользователя игрового сервера это нормально; для www-data или другой учётной записи, которую система делит между службами, так делать не стоит.
Общая группа. Когда писать нужно и человеку, и службе, поместите их в общую группу и сделайте дерево доступным для записи группе:
# a group for everyone who edits this server$ sudo groupadd gameadmins$ sudo usermod -aG gameadmins alice$ sudo usermod -aG gameadmins steam# hand the tree to the service user and the shared group$ sudo chown -R steam:gameadmins /srv/game$ sudo chmod -R g+rwX /srv/game# new files inside inherit the group, not the creator's own group$ sudo find /srv/game -type d -exec chmod g+s {} +Заглавная X в g+rwX добавляет исполнение только папкам и файлам, у которых оно уже было, так что не все конфиги становятся исполняемыми. Бит g+s (setgid) на папках означает, что всё созданное внутри принадлежит группе gameadmins, а не группе того, кто это создал. Членство в группе считывается при входе, поэтому alice должна отключиться и подключиться заново, чтобы оно подействовало - на этом шаге теряется на удивление много времени.
Setgid исправляет группу, но не права. Если служба по-прежнему создаёт файлы с 644, они окажутся в нужной группе, но без записи для группы. Задайте службе umask 002: для юнита systemd это UMask=0002 в секции [Service], затем systemctl daemon-reload и перезапуск. Для загружаемых вами файлов OpenSSH позволяет задать umask самой SFTP-сессии через ForceCommand internal-sftp -u 0002 или Subsystem sftp internal-sftp -u 0002 в sshd_config.
Используйте ACL, когда модель с группами становится неудобной (несколько служб, у каждой своё дерево). ACL по умолчанию на папке действует на всё, что будет создано в ней позже:
$ sudo setfacl -R -m u:alice:rwX /srv/game$ sudo setfacl -R -d -m u:alice:rwX /srv/game$ getfacl /srv/game/server.propertiesACL отображаются как + в конце строки прав в ls -l (-rw-rw-r--+), а многие SFTP-клиенты их вообще не показывают, и об этом стоит помнить, когда видимые права противоречат тому, что происходит на самом деле.
Чего делать не нужно: chmod -R 777. Это делает каждый файл доступным для записи любой учётной записи и любому скомпрометированному процессу на машине, и к тому же не переживёт следующий файл, который создаст служба. Другое плохое решение - запустить службу от root, чтобы она "писала куда угодно", - разобрано в разделе о владельцах в статье о правах, и коротко суть в том, что тогда уязвимый плагин получает всю машину. Несколько игровых серверов на одном VDS описывает схему "один пользователь на сервер", благодаря которой всё это становится предсказуемым.
Chroot SFTP: папка, в которую вы попали, вам не принадлежит#
Chroot-SFTP часто встречается на общем и самодельном хостинге: пользователь заперт в одной папке и не видит остальную систему. Обычная конфигурация выглядит так:
Match User alice ChrootDirectory /srv/sftp/alice ForceCommand internal-sftp AllowTcpForwarding no X11Forwarding noOpenSSH требует, чтобы chroot-каталог и все каталоги выше него принадлежали root и не были доступны для записи никому другому, ни пользователю, ни группе. Если это не так, вход не удаётся, а в журнале авторизации сервера появляется bad ownership or modes for chroot directory. Следствие - классическая жалоба на chroot: пользователь входит, попадает в / и ничего не может загрузить, потому что / внутри "тюрьмы" - это принадлежащий root каталог, в который ему по замыслу писать нельзя.
Решение - доступный для записи подкаталог внутри "тюрьмы":
$ sudo chown root:root /srv/sftp/alice$ sudo chmod 755 /srv/sftp/alice$ sudo mkdir /srv/sftp/alice/upload$ sudo chown alice:alice /srv/sftp/alice/uploadДальше пользователи пишут в /upload. Если файлам нужно попасть в настоящую папку приложения, используйте bind mount, а не символическую ссылку: ссылка, указывающая за пределы "тюрьмы", разрешается внутри неё и никуда не ведёт.
Read-only монтирование, полный диск и неизменяемые файлы#
Иногда права в порядке, владелец в порядке, а запись всё равно не удаётся. Три причины лежат ниже уровня прав.
Файловая система только для чтения. Ошибка выглядит как Read-only file system (EROFS), хотя некоторые SFTP-клиенты сводят её к общему сбою или даже к permission denied. Проверьте параметры монтирования:
$ findmnt -no OPTIONS --target /srv/gamero,relatimeТом может быть смонтирован как ro намеренно (сетевой ресурс, ISO-образ, том контейнера, подключённый только для чтения), но если файловая система была доступна для записи вчера, а сегодня стала ro, это обычно значит, что ядро перемонтировало её после обнаружения ошибки диска. Это проблема оборудования или хоста, а не настроек; посмотрите dmesg и не пишите на этот том, пока причина не ясна.
Полный диск или закончились inode. Запись не удаётся, когда нет места, и многие клиенты сообщают об этом плохо: оборванная загрузка, файл нулевого размера после сохранения или невнятная ошибка вместо No space left on device. Проверьте и байты, и inode:
$ df -h /srv/game$ df -i /srv/gameНа ext4 есть нюанс: по умолчанию около 5% блоков зарезервировано для root. При заполнении на 96% процесс root ещё может писать, а ваш пользователь уже нет, и это выглядит в точности как проблема с правами. Как найти, что заняло место, описано в статье Game server disk space full.
Неизменяемый файл. chattr +i делает файл неизменяемым даже для root, и ошибка выглядит как Operation not permitted. Некоторые администраторы используют это, чтобы игра не переписывала конфиг, а потом забывают. Проверьте и снимите флаг из shell:
$ lsattr /srv/game/server.properties----i---------e------- /srv/game/server.properties$ sudo chattr -i /srv/game/server.propertiesВ дистрибутивах с включённым SELinux (Fedora, RHEL и его пересборки) есть ещё один слой: файлу с неверным контекстом безопасности можно отказать, даже если права это позволяют. ls -Z показывает контекст, а виноваты обычно файлы, которые не скопировали, а переместили на место.
Редакторы, сохраняющие через временный файл#
Частый и запутанный случай: файл можно перезаписать загрузкой, но сохранение из редактора не удаётся, или наоборот. Причина в том, что "сохранение" - это не одна операция. Многие инструменты записывают новый файл рядом с оригиналом, а затем переименовывают его поверх старого, чтобы обрыв соединения не оставил наполовину записанный конфиг. Для этого нужен w на папку. Если у вас есть доступ на запись к файлу, но не к его папке, запись на месте проходит, а сохранение через временный файл - нет.
WinSCP по умолчанию так и загружает файлы: передача идёт в name.filepart, а по завершении файл переименовывается. Параметр находится в Preferences, Transfer, Endurance, как "Enable transfer resume/transfer to temporary filename". Если выбрать Disable, WinSCP будет писать прямо в целевой файл, и это работает, когда доступен для записи только сам файл. Кроме того, после загрузки WinSCP пытается установить права и время изменения; если записывать файл можно, а менять его атрибуты нельзя, он сообщает, что загрузка прошла успешно, но установить права или время не удалось. Загрузка при этом сработала. В настройках передачи есть параметр "Ignore permission errors"; можно также снять "Set permissions" и "Preserve timestamp" для этого подключения.
FileZilla пишет на месте, так что проблема временных файлов её почти не касается; её "View/Edit" скачивает локальную копию и загружает её снова при сохранении, а это обычная загрузка по обычным правилам. Если FileZilla показывает open for write: permission denied, значит, файл или его папка действительно недоступны для записи вашему пользователю.
Расширения редакторов и другие инструменты ведут себя по-разному. SFTP-расширения для VS Code, плагины Notepad++ и монтирования sshfs у каждого своя стратегия, а некоторые ещё и пытаются сохранить исходные права файла при записи. Если один инструмент работает, а другой на том же файле нет, считайте причиной временный файл или атрибуты, а не то, что сервер изменился.
Есть и обратная ловушка: клиент, настроенный выставлять фиксированные права при загрузке, может незаметно менять режимы. Если скрипт теряет бит исполнения при каждой загрузке, ищите причину в настройках прав при загрузке в клиенте, а не на сервере.
На игровой панели в стиле Pterodactyl#
Панели на основе Pterodactyl и Wings не используют OpenSSH для доступа к файлам. Wings запускает собственную SFTP-службу, к имени пользователя добавляется короткий id сервера (alice.1a2b3c4d), порт обычно 2022, а не 22, и за ней нет shell. Каждый файл принадлежит единственному непривилегированному пользователю, от имени которого работает контейнер сервера, - тому, что в листингах отображается как container, - и всё, что вы загружаете, автоматически получает этого владельца. Поэтому проблем "файл создан root" и "пользователь службы против моего пользователя" здесь не бывает. chown недоступен и не нужен; chmod работает для установки прав вроде 755 на скрипт.
Когда запись на панели не удаётся, причины другие:
| Симптом | Вероятная причина |
|---|---|
| Список и скачивание работают, загрузить ничего нельзя | У вашей учётной записи субпользователя нет права создавать или изменять файлы |
| Новые файлы создаются, существующие перезаписать нельзя | Создание разрешено, изменение нет |
| Нельзя удалить или переименовать | Нет права на удаление |
| Один конкретный файл всегда отклоняется | Он указан в списке запрещённых файлов egg-а сервера |
| Загрузки не удаются или обрываются, хотя раньше работали | Достигнут лимит диска |
| Сам вход отклоняется | Нет права на SFTP или неверный формат имени пользователя |
Pterodactyl делит доступ к файлам на отдельные права - чтение, чтение содержимого, создание, изменение, удаление, архивирование и сам SFTP, - и SFTP-служба проверяет те же права, что и файловый менеджер в браузере. Субпользователь с правами на чтение и SFTP, но без права на изменение, получает именно ту ситуацию "подключился, но не могу редактировать". Владелец сервера исправляет это, изменив права этого человека, а не что-либо в файлах. Что и кому выдавать, описано в статье Subusers and least privilege.
Список запрещённых файлов egg-а - вторая причина, специфичная для панелей. Автор egg-а может пометить файлы, которые пользователям сервера трогать нельзя (часто это файл лицензии или стартовый скрипт, которым управляет хостинг), и SFTP-служба отклоняет их с ошибкой доступа даже для владельца сервера. Если всегда отклоняется ровно один файл, а соседние в порядке, подозревайте в первую очередь это. Что именно контролирует egg, объясняет статья Pterodactyl eggs for game servers.
В RE:NODE SFTP доступен на каждом сервере, а учётные данные выдаются на каждый сервер, а не на аккаунт; параметры подключения указаны на сервере в панели. Доступ для других людей настраивается через роли, команды и гранты с детальными правами на файлы, так что режим "только файлы, без удаления" - реальная настройка. Когда показатель диска сервера достигает лимита, запись прекращается; графики в консоли показывают диск относительно лимита, и это самый быстрый способ подтвердить или исключить эту причину. Руководство по файлам рассматривает файловый менеджер и SFTP бок о бок, а SFTP and the file manager - клиенты, передачу файлов по скриптам и файлы, которые запущенный сервер держит открытыми.
Чек-лист, который находит причину за пять минут#
Идите по списку сверху вниз и остановитесь на первом, что окажется неверным:
- Это ошибка входа?
Permission denied (publickey,password)означает аутентификацию, а не файлы. - Отказ на всех файлах или на одном? Если отказ везде, дело в вашей учётной записи, монтировании или диске. Если на одном файле - в его владельце, правах, флаге неизменяемости или в запрете на панели.
- Кто вы и кто владелец?
id, затемls -laдля файла и его папки. Сравните владельца, группу и биты, которые к вам относятся. - Папка доступна для записи? Новые файлы, удаление, переименование и сохранение через временный файл требуют
wна каталог. - Диск полон или только для чтения?
df -h,df -i,findmnt. На панели - график диска. - Файл неизменяемый?
lsattr. - Другой клиент ведёт себя иначе? Если да, посмотрите на загрузку через временные файлы и настройки атрибутов в том клиенте, где не работает.
- На панели: что может ваша учётная запись? Попросите владельца проверить ваши права на файлы.
Каждый шаг - одна команда или один экран, и порядок важен: он идёт от дешёвых и частых причин к редким.
FAQ#
Почему по SFTP можно скачивать, но нельзя загружать?
Для скачивания нужно право чтения на файл; для загрузки - право записи на целевую папку. Права по умолчанию (644 для файлов, 755 для папок) дают чтение всем, а запись только владельцу. Если вы входите под другим пользователем, не тем, кто владеет папкой, получается именно это. Войдите как владелец или разделите с ним группу.
Исправит ли chmod 777 ошибку SFTP permission denied?
Он часто прячет симптом и всегда создаёт проблему побольше. Любой пользователь и процесс на машине сможет переписать эти файлы, а новые файлы, созданные службой, всё равно приходят с обычными правами, так что проблема вернётся. Общая группа с папками setgid и umask 002 решает её правильно.
Почему WinSCP пишет, что загрузка прошла, но установить права не удалось?
Вы можете записать файл, но не менять его атрибуты, обычно потому, что вы не его владелец. Содержимое при этом загружено. Включите "Ignore permission errors" в настройках передачи или отключите установку прав и времени при загрузке для этого сайта.
Я не могу загрузить файл в корневую папку после входа в chroot-аккаунт. Это сломано?
Нет. OpenSSH требует, чтобы chroot-каталог принадлежал root и не был доступен пользователю для записи, поэтому верхний уровень по замыслу только для чтения. Администратору нужно создать внутри "тюрьмы" подкаталог, принадлежащий вашему пользователю, и вы загружаете файлы туда.
Почему на игровой панели одни файлы можно редактировать, а другие нет?
Либо у вашей учётной записи субпользователя есть одни права на файлы и нет других (например, создание без изменения), либо файл входит в список запрещённых файлов egg-а. Владелец тут ни при чём: на панели на базе Pterodactyl каждый файл в папке сервера принадлежит одному и тому же пользователю контейнера.
Может ли полный диск вызвать permission denied?
Буквально нет, но многие SFTP-клиенты сообщают о неудачной записи расплывчато, а на ext4 блоки, зарезервированные для root, приводят к тому, что почти полный диск отказывает обычным пользователям раньше, чем root. Проверьте df -h и df -i, прежде чем менять какие-либо права.


