#Что означает ошибка
readonly database
«attempt to write a readonly database» значит, что процесс не может записывать в файл базы или в её каталог. SQLite создаёт временные файлы (-journal, -wal, -shm) рядом с базой, поэтому права на каталог так же важны, как права на файл.
Чаще всего причина — владелец файла не совпадает с пользователем веб-сервера.
Иногда файловая система смонтирована только для чтения.
Файл или каталог базы недоступны для записи пользователю веб-сервера. Выдайте права на файл и каталог (нужны для журнала).
#Причины и решения
| Возможная причина | Как узнать | Что делать |
|---|---|---|
| Нет прав на файлchmod. | Пользователь службы не имеет права писать в файл либо каталог | Проверьте владельца конкретного процесса и настройте минимальные права. |
| Нет прав на каталогЖурнал. | Файловая система смонтирована ro либо закончился диск/inode | Изучите findmnt, df и журналы ядра; не перемонтируйте вслепую. |
| Файловая система read-onlyМонтирование. | Docker том смонтирован как read-only или UID не совпадает | Проверьте mounts и пользователя контейнера. |
| SELinuxКонтекст. | SELinux/AppArmor запретил доступ к файлам | Изучите подтверждённые сообщения аудита, не отключайте защиту. |
#Пошаговое решение
- Проверьте владельца файла и каталогаЭто проверка для владельца сервера или разработчика, имеющего доступ к файлу SQLite; обычному посетителю сайта менять права нельзя. Сначала выясните абсолютный путь к базе в настройках приложения и имя системного пользователя, под которым запускается веб-сервер/служба (например, по настройке systemd
User=или процессу PHP-FPM). На Linux в терминале выполнитеls -ld /путь/к/каталогуиls -l /путь/к/каталогу/app.db, подставив реальные пути. Проверьте права на сам файл, каталог и родительские каталоги: процессу могут быть нужны права создания соседних файлов-wal/-shmили журнала. Ничего пока не меняйте. - Выдайте права пользователю процессаЕсли по результатам шага 1 права недостаточны, сделайте резервную копию штатным
.backup, согласуйте пользователя процесса и исправьте доступ точечно, а не на всём сайте. Например, администратор Linux может задать владельца конкретной базыsudo chown appuser:appgroup /srv/app/data/app.dbи каталога/srv/app/data, ноappuser,appgroupи пути здесь заглушки; используйте действительные значения. Не применяйтеchmod -R 777или смену владельца корня сайта: это создаёт уязвимости. После исправления проверьте запись через функциональность приложения, не выполняя непроверенных SQL над рабочими данными. - Проверьте, не только ли чтение файловая системаЕсли разрешения правильные, проверьте состояние файловой системы:
findmnt -T /полный/путь/к/app.dbпокажет точку монтирования и параметры,df -hиdf -i— свободное место и inode,dmesg/journalctl -k— сообщения ядра (иногда нужны права администратора). Если раздел перешёл вro, есть ошибки носителя или закончилось место, остановите записи и разберитесь с инфраструктурой. Не перемонтируйте том вrw«на всякий случай» и не запускайте fsck по смонтированному рабочему разделу. - Проверьте SELinux и Docker-томаВ Docker проверьте
docker inspect ИМЯ_КОНТЕЙНЕРА(подставьте его) и настройкиvolumes:в compose-файле: каталог или файл SQLite не должен быть смонтирован как:ro, если нужны записи. Сверьте пользователя внутри контейнера и права тома на хосте. В системе с SELinux/ AppArmor изучите журналы запретов у администратора — без подтверждённой причины не отключайте защиту и не запускайте массовыйchcon. На Windows дополнительно проверьте атрибут «Только чтение», права учётной записи службы и расположение базы. - Перезапустите сервисКогда выявленная причина устранена, запустите приложение штатным способом и повторите действие, которое должно записать данные; затем прочитайте только что созданную запись и проверьте логи. Перезапуск службы нужен лишь тогда, когда изменена конфигурация или работающий процесс не подхватил права/том; предварительно предупредите пользователей. Если сохраняется
readonly, получите расширенный код ошибки SQLite (например,SQLITE_READONLY_DIRECTORY) и уточните точный путь открываемой базы, чтобы не чинить другую копию.
#Права
Прежде чем менять доступ, установите реальный абсолютный путь БД, пользователя процесса и режим журналирования, затем выполните ls -l для файла и ls -ld для каталога. Нельзя автоматически назначать владельца www-data или права 775: PHP-FPM может работать от другого пользователя, а дополнительные права создадут угрозу. Используйте штатную резервную копию и точечную настройку доступа.
#Файловая система и защита
Проверьте findmnt -T для точного файла, df -h/df -i, журнал ядра и параметры тома Docker. Для SELinux сначала изучите записи аудита; не выполняйте произвольный chcon и не отключайте защиту. На Windows проверьте ACL учётной записи конкретной службы, а не только флаг «Только чтение».
#Откройте базу корректно
Если приложение открывает SQLite в URI-режиме mode=ro, запись не предусмотрена и необходимо выяснить, почему выбран этот режим. Блокировка другими процессами чаще порождает database is locked, а не readonly. Не убивайте держателей файла без диагностики. После согласованного исправления пути или прав перезапускать сервис нужно только при необходимости.
# Диагностика на Linux: подставьте существующий абсолютный путьls -ld /srv/app/datals -l /srv/app/data/app.dbfindmnt -T /srv/app/data/app.dbdf -h /srv/app/data