I created a user called breti which contains the website.
When I run python manage.py runserver from the breti account, it works perfectly!
I configured Apache to use the breti user and group. It works because I created a “whoami” view that queries os.environ[“USER”] and returns “breti”.
And yet, as soon as I try to log in from apache:
attempt to write a readonly database
I don’t think it’s a permission issue because even when I run chmod -R 777, I get exactly the same error!
Any idea?
Please post all of the Apache directives for your Django project.
Thank you, this is a minimalist version of /etc/apache2/sites-available/breti.conf:
WSGIDaemonProcess breti \
user=breti \
group=breti \
python-home=/home/breti/.pyenv/versions/breti \
python-path=/home/breti/site \
processes=1 \
threads=1
WSGIProcessGroup breti
WSGIScriptAlias / /home/breti/site/breti/wsgi.py
<VirtualHost *:80>
ServerName breti-modelisme.org
ServerAlias www.breti-modelisme.org 127.0.0.1 localhost
ErrorLog ${APACHE_LOG_DIR}/breti_error.log
CustomLog ${APACHE_LOG_DIR}/breti_access.log combined
Protocols h2 http/1.1
<Directory /home/breti/site/breti>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
Alias /static /home/breti/site/static
<Directory /home/breti/site/static>
Require all granted
</Directory>
</VirtualHost>
Idem for *:443.
I’m assuming you’re using SQLite as the database?
What directory is that file in?
What are the permissions on that directory?
Yes, I’m using SQLite3:
DATABASES = {
“default”: {
“ENGINE”: “django.db.backends.sqlite3”,
“NAME”: BASE_DIR / “db.sqlite3”,
}
}
The project is in /home/breti/site and the database is /home/breti/site/db.sqlite3
I try different permissions, including 777! The result still the same.
When I try to edit the database from /home/breti/site/breti/wsgi.py directly with sqlite3, it works!
Please show the permissions on the file itself and on the containing directory.
Also, what operating system are you running this on? Do you have something like SELinux or AppArmor involved?
Check syslog to see if there is any more detailed log information available.
I can give a little bit more information of the trace-back:
Traceback (most recent call last):
File “/home/breti/.pyenv/versions/breti/lib/python3.14/site-packages/django/db/backends/utils.py”, line 105, in _execute
return self.cursor.execute(sql, params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/home/breti/.pyenv/versions/breti/lib/python3.14/site-packages/django/db/backends/sqlite3/base.py”, line 359, in execute
return super().execute(query, params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The above exception (attempt to write a readonly database) was the direct cause of the following exception:
File “/home/breti/.pyenv/versions/breti/lib/python3.14/site-packages/django/core/handlers/exception.py”, line 55, in inner
response = get_response(request)
^^^^^^^^^^^^^^^^^^^^^
File “/home/breti/.pyenv/versions/breti/lib/python3.14/site-packages/django/core/handlers/base.py”, line 198, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/home/breti/site/account/views.py”, line 44, in login_page
profile.save()
And the local vars:
profile: <Profil: Profil object (1)>
Any other ideas? 
Also, from a view, when I try to write on the database, it works!
with sqlite3.connect("/home/breti/site/db.sqlite3") as conn:
conn.execute("CREATE TABLE IF NOT EXISTS table_wsgi (id INTEGER PRIMARY KEY AUTOINCREMENT);")
This is extremely useful information.
I would specifically check syslog here to see what file it trying to be written. It’s possible that your configuration isn’t referring to the database file that you think it is.
Thank you for your perseverance!
In the syslog /var/log/apache2/breti_error.log, there is:
[Mon Feb 09 11:04:15.206933 2026] [wsgi:error] [pid 89791:tid 89905] [remote 131.254.20.88:49066] sqlite3.OperationalError: attempt to write a readonly database
[Mon Feb 09 11:04:15.206961 2026] [wsgi:error] [pid 89791:tid 89905] [remote 131.254.20.88:49066] profile.save() # TODO: c’est ici que arrive “attempt to write a readonly database”
- Im a runing on debian:
- OS: Debian GNU/Linux forky/sid (forky) x86_6
- Kernel: Linux 6.18.5+deb14-amd64
- Disk (/home): 383.24 GiB / 573.88 GiB (67%) - btrfs
-
“referring to the database file that you think it is”. Actually, it could have!
So I check the variable: DATABASES[“default”][“name”], It and unfortunately that’s correct…
I also deleted the database and all migrations to start from scratch, but nothing has changed!
-
Change sqlite3 for MySQL
When I change the old config:
DATABASES = {
“default”: {
“ENGINE”: “django.db.backends.sqlite3”,
“NAME”: BASE_DIR / “db.sqlite3”,
}
}
By that one:
DATABASES = {
“default”: {
“ENGINE”: “django.db.backends.mysql”,
“NAME”: “breti_database”, # database name
“USER”: “breti”,
“PASSWORD”: “…”,
“HOST”: “127.0.0.1”, # TCP, not socket
“PORT”: “3306”, # default MySQL port
}
}
It Works!!!
But using a mariadb database is realy overkill for my project, and it dosen’t solve the issue of sqlite…
But maybe it can give you some clues?
That’s your apache log, that’s not syslog (/var/log/syslog)
There should be something in there that identifies the operation attempting to be performed, and the actual file attempting to be accessed.
As a quick test, you could try creating the database in a “neutral” directory (not inside your home directory) where you can grant permissions 777 on both the database file and the enclosing directory. (Perhaps create a directory in /var for this.) I would also suggest adding breti to the www-data group, and set the group ownership of this new directory to www-data.
Also, how are you running Apache? Are you using systemd? An init script? Something else?
-
sudo cat /var/log/apache2/breti_error.log | grep “Mon Feb 09 11:04”
It gives me exactly the same python traceback as the previous messages. I don’t see any new informations.
-
Well done thank you! I just created the folder /var/database with root, then change owner sudo chowm breti /var/database and the permissions sudo chmod -R 755 /vat/database. Then, from the user breti, I created the database with python manage.py migrate.
And ok!, now there is no problem to write it from apache2.
So, If sudo chmod -R 777 /home/breti, how to set the correct permission to live the database in /home/breti/site/db.sqlite3 ? But then, why does calling sqlite3.connect from a view not behave the same as calling profile.save() form the same view
???
In the general case, you never want to do this. You absolutely do not want your web site to be able to change files in your project directory - it makes you vulnerable to a whole class of possible exploits. (You want all mutable directories to be completely outside your project. This includes your media directory as well.)
In this specific case, there’s something involved here that goes beyond the traditional “simple” file permissions which is why I was asking about things like AppArmor or SELinux, and how you are specifically running Apache itself.
No idea. (I could make some guesses, but they’d be very uninformed. I don’t have near enough knowledge and information about your platform.)
Well, we can consider this issue resolved, even if some strange things are not fully understood.
For future reference, I run apache2 with systemctl.
Summary:
If there are read-only issues with the SQLite database via Apache2, one solution is to move the database to /var with the correct permissions.