#Что происходит и когда возникает
После переноса SQLite-файла на Linux-сервер SELECT может работать, а INSERT/UPDATE — возвращать «attempt to write a readonly database» или SQLITE_READONLY_DIRECTORY. SQLite для записи часто нужны права не только на сам файл, но и на содержащий его каталог — для создания файлов журнала, -wal или -shm. Права нужно проверять от имени процесса PHP-FPM, Python либо службы, а не от собственного административного пользователя.
#Возможные причины: как различить
| Возможная причина | Как узнать | Что делать |
|---|---|---|
| Файл принадлежит другой учётной записиАрхив или копирование сохранили владельца, который не совпадает с пользователем службы. | ls -l показывает владельца, не имеющего отношения к учётной записи веб-приложения. | Дать минимально необходимые права назначенному пользователю после согласования. |
| Нет прав записи на каталогSQLite не удаётся создать журнал или файл -shm; ошибка может возникнуть при наличии прав на .db. | ls -ld показывает каталог, недоступный на запись для службы. | Исправить доступ к конкретному каталогу, а не ко всей системе. |
| Соединение открыто в режиме read-onlyСтрока подключения содержит mode=ro/immutable=1 либо приложение монтирует каталог только для чтения. | Режим открытия прямо задан в коде или конфигурации. | Исправить режим только для службы, которой разрешена запись. |
#Пошаговая диагностика и исправление
- Не меняйте права до проверки назначения файлаПосле переноса сохраните полный путь к SQLite-файлу и сообщение об ошибке. Выясните, какой процесс должен записывать: PHP-FPM конкретного сайта, пользователь службы или отдельный контейнер. Если приложение только читает данные, read-only может быть намеренной защитой — в таком случае права менять не нужно.
- Проверьте режим открытия в приложенииНайдите строку подключения в настройках (не публикуя пароли): sqlite:///путь, URI file:...?...mode=ro, опции immutable и режим монтирования контейнера. Если явно указан mode=ro, запись невозможна независимо от chmod. Исправляйте конфигурацию только после подтверждения, что процесс действительно должен выполнять запись.
- Убедитесь, что используется нужный файлОткройте штатную SQL-консоль приложения и выполните PRAGMA database_list;. Если main указывает на тестовую копию или неожиданный относительный путь, исправьте путь в настройках и проверьте снова. Не создавайте второй файл под похожим именем.
- Проверьте файл и родительский каталог в LinuxНа сервере откройте терминал под учётной записью с разрешением на диагностику. Выполните ls -ld для каталога и ls -l для файла базы. Сравните владельца и группу с фактической учётной записью службы. Команды только показывают права и не требуют root, если каталоги доступны на просмотр. Если пути закрыты, обратитесь к администратору.
- Учтите WAL и прочие служебные файлыЕсли PRAGMA journal_mode возвращает wal, SQLite может создавать -wal и -shm в каталоге. Проверьте свободное место и права доступа к ним без ручного удаления. В режиме только чтения SQLite версии 3.22+ иногда может читать WAL при особых условиях, но это не означает возможность записывать.
- Исправьте доступ точечно через администратораПосле резервной копии администратор должен выделить отдельный каталог данных вне общедоступной директории, назначить необходимого владельца/группу и минимальные права на конкретный каталог и файл. Не используйте chmod 777 и chown -R на большом дереве. На хостинге или с SELinux/AppArmor отдельно проверьте применяемые политики и журнал отказов.
- Проверьте запись безопасным штатным действиемПосле изменения разрешений выполните предусмотренную приложением тестовую операцию в тестовой базе и проверьте результат чтением; для рабочей базы используйте только безопасное штатное действие, которое можно отменить. Если ошибка осталась, верните исходные права из зафиксированного состояния и обратитесь к администратору с путём, правами и ошибкой.
#Команды и проверочные примеры
ls -ld /srv/app/datals -l /srv/app/data/app.dbPRAGMA database_list;PRAGMA journal_mode;#Как проверить результат
INSERT/UPDATE в специально выделенной тестовой базе проходят без SQLITE_READONLY, контрольная запись читается после открытия нового соединения, а служба не получила доступ к чужим каталогам. В рабочем приложении подтвердите исправление штатным действием.
#Если не помогло
При продолжающемся отказе проверьте доступ к родительским каталогам по всей цепочке, контекст SELinux/AppArmor, режим монтирования тома и квоту диска. Не пытайтесь исправить права единым chmod -R; подготовьте диагностические данные для администратора.