sissbruecker / linkding

Self-hosted bookmark manager that is designed be to be minimal, fast, and easy to set up using Docker.
MIT License
5.36k stars 263 forks source link

Error backing up: `sqlite3.OperationalError: unable to open database file` #626

Closed bphenriques closed 4 months ago

bphenriques commented 5 months ago

Hello,

Short

I am facing a sqlite3.OperationalError: unable to open database file error when running:

$ docker exec -it linkding python manage.py backup backup.sqlite3

I have followed the official guide. I thought it was permissions problem but does not seem to be the case. See below the longer response.

Longer

I have a local environment where I am testing a backup solution using docker-compose.yml:

  linkding:
    image: sissbruecker/linkding:latest
    container_name: linkding
    hostname: linkding
    user: "${PUID}:${PGID}"
    environment:
      LD_SUPERUSER_NAME: bphenriques
    volumes:
      - "/tmp/home-server/linkding:/etc/linkding/data"
    restart: unless-stopped
    env_file:
      - secrets.env.example
    ports:
      - "3005:9090"

And I created the script that boils down to docker exec -u "${PUID}:${PGID}" -it linkding python manage.py backup backup.sqlite3. PUID and PGID prints to 1000 and 100, respectively.

Leading to:

Traceback (most recent call last):
  File "/etc/linkding/manage.py", line 21, in <module>
    main()
  File "/etc/linkding/manage.py", line 17, in main
    execute_from_command_line(sys.argv)
  File "/opt/venv/lib/python3.10/site-packages/django/core/management/__init__.py", line 446, in execute_from_command_line
    utility.execute()
  File "/opt/venv/lib/python3.10/site-packages/django/core/management/__init__.py", line 440, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/opt/venv/lib/python3.10/site-packages/django/core/management/base.py", line 402, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/opt/venv/lib/python3.10/site-packages/django/core/management/base.py", line 448, in execute
    output = self.hanthe user and group matches the db.sqlite3dle(*args, **options)
  File "/etc/linkding/bookmarks/management/commands/backup.py", line 20, in handle
    backup_db = sqlite3.connect(destination)
sqlite3.OperationalError: unable to open database file

My first impressions were permissions issues, but then I added the -u flag to be consistent with the docker-compose.yml file with no success. I then entered the container and checked permissions and it seems fine:

On the container:

$ python manage.py backup output.sqlite3    
Traceback (most recent call last):
  File "/etc/linkding/manage.py", line 21, in <module>
    main()
  File "/etc/linkding/manage.py", line 17, in main
    execute_from_command_line(sys.argv)
  File "/opt/venv/lib/python3.10/site-packages/django/core/management/__init__.py", line 446, in execute_from_command_line
    utility.execute()
  File "/opt/venv/lib/python3.10/site-packages/django/core/management/__init__.py", line 440, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/opt/venv/lib/python3.10/site-packages/django/core/management/base.py", line 402, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/opt/venv/lib/python3.10/site-packages/django/core/management/base.py", line 448, in execute
    output = self.handle(*args, **options)
  File "/etc/linkding/bookmarks/management/commands/backup.py", line 20, in handle
    backup_db = sqlite3.connect(destination)
sqlite3.OperationalError: unable to open database file
$ ls -la /etc/linkding/data
total 392
drwxr-xr-x 3 1000 users   4096 Feb  8 12:49 .
drwxrwxr-x 1 root root    4096 Feb  8 12:49 ..
-rw-r--r-- 1 1000 users 303104 Jan 27 08:24 db.sqlite3         # Note: seems readable
-rw-r--r-- 1 1000 users  32768 Feb  8 12:49 db.sqlite3-shm
-rw-r--r-- 1 1000 users  45352 Feb  8 12:49 db.sqlite3-wal
drwxr-xr-x 2 1000 users   4096 Jan 27 08:24 favicons
$ id
uid=1000 gid=100(users) groups=100(users)                    # Note: the user and group matches the db.sqlite3

On my host:

$ ls -la /tmp/home-server/linkding/
total 392
drwxr-xr-x  3 bphenriques users   4096 Feb  8 12:49 .
drwxr-xr-x 20 bphenriques users   4096 Feb  4 18:08 ..
-rw-r--r--  1 bphenriques users 303104 Jan 27 08:24 db.sqlite3
-rw-r--r--  1 bphenriques users  32768 Feb  8 12:49 db.sqlite3-shm
-rw-r--r--  1 bphenriques users  45352 Feb  8 12:49 db.sqlite3-wal
drwxr-xr-x  2 bphenriques users   4096 Jan 27 08:24 favicons
$ id bphenriques
uid=1000(bphenriques) gid=100(users) groups=100(users),1(wheel),57(networkmanager),131(docker)   # Note: matches the ids inside the container

Thank you :bow:

Edit: for this local test environment I added a single bookmark so there is something in the db.

bphenriques commented 5 months ago

Ok, noticed taht the stacktrace points to line 20: https://github.com/sissbruecker/linkding/blob/master/bookmarks/management/commands/backup.py#L20

~Perhaps the error occurs because there is no file which is expected as we are in the process of creating a new one?~ looked online and the API creates a new file allegedly

bphenriques commented 5 months ago

Found the error, The /etc/linkding folder (the default path for backups) is always owned by the root inside the container. However, for users that are not running the docker as root, we should actually have permissions to the /etc/linkding/data as part of the volume mounting process.

Having that said the following commands are now working:

$  docker exec -it linkding python manage.py backup /etc/linkding/data/backup.sqlite3
Copied 50 of 74 pages...
Copied 74 of 74 pages...
Backup created at /etc/linkding/data/backup.sqlite3
$  docker cp linkding:/etc/linkding/data/backup.sqlite3 "${target_dir}/linkding/backup.sqlite3"
                                               Successfully copied 305kB to /tmp/tmp.uBybe7ECaH.restic-backup/linkding/backup.sqlite3

Suggestion: add a note to the documentation for users running docker without root