linuxserver / docker-bookstack

A Docker container for the BookStack documentation wiki
GNU General Public License v3.0
725 stars 105 forks source link

[BUG] production.ERROR: Error when attempting image upload:Unable to create a directory at /app/www/public/uploads/images /user/2023-10 #191

Closed HC-Pinky closed 9 months ago

HC-Pinky commented 9 months ago

Is there an existing issue for this?

Current Behavior

No upload of images possible (avatar, attachments to books, inplace images in books etc.)

Expected Behavior

Uploading images should work as expected

Steps To Reproduce

Installed Bookstack via docker compose opened Browser, logged in, went to Edit Profile and upload a new avatar image. --> Error message pops up that no sufficient write permissions exist (same for uploading images in books)

Here the Message from the logs:

[2023-10-02 21:54:43] production.ERROR: Error when attempting image upload:Unable to create a directory at /app/www/public/uploads/images /user/2023-10.
[2023-10-02 21:54:43] production.ERROR: File path /uploads/images/user/2023-10/rick-256.png could not be uploaded to. Ensure it is writab le to the server. {"userId":1,"exception":"[object] (BookStack\Exceptions\ImageUploadException(code: 0): File path /uploads/images/user /2023-10/rick-256.png could not be uploaded to. Ensure it is writable to the server. at /app/www/app/Uploads/ImageService.php:174) [stacktrace]

0 /app/www/app/Uploads/ImageService.php(128): BookStack\Uploads\ImageService->saveNew()

1 /app/www/app/Uploads/ImageRepo.php(119): BookStack\Uploads\ImageService->saveNewFromUpload()

2 /app/www/app/Users/Controllers/UserController.php(159): BookStack\Uploads\ImageRepo->saveNew()

3 /app/www/vendor/laravel/framework/src/Illuminate/Routing/Controller.php(54): BookStack\Users\Controllers\UserController->update()

4 /app/www/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(43): Illuminate\Routing\Controller->callAction()

5 /app/www/vendor/laravel/framework/src/Illuminate/Routing/Route.php(259): Illuminate\Routing\ControllerDispatcher->dispatch()

6 /app/www/vendor/laravel/framework/src/Illuminate/Routing/Route.php(205): Illuminate\Routing\Route->runController()

7 /app/www/vendor/laravel/framework/src/Illuminate/Routing/Router.php(798): Illuminate\Routing\Route->run()

8 /app/www/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(141): Illuminate\Routing\Router->Illuminate\Routing\{closur

e}()

9 /app/www/app/Http/Middleware/Authenticate.php(23): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()

10 /app/www/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): BookStack\Http\Middleware\Authenticate->handle()

11 /app/www/app/Http/Middleware/Localization.php(45): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()

12 /app/www/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): BookStack\Http\Middleware\Localization->handle()

13 /app/www/app/Http/Middleware/RunThemeActions.php(26): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()

14 /app/www/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): BookStack\Http\Middleware\RunThemeActions->handle()

15 /app/www/app/Http/Middleware/CheckEmailConfirmed.php(47): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()

16 /app/www/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): BookStack\Http\Middleware\CheckEmailConfirmed->handle

()

17 /app/www/app/Http/Middleware/PreventAuthenticatedResponseCaching.php(21): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{clos

ure}()

18 /app/www/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): BookStack\Http\Middleware\PreventAuthenticatedRespons

eCaching->handle()

19 /app/www/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php(78): Illuminate\Pipeline\Pipeline->

Illuminate\Pipeline\{closure}()

20 /app/www/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\Foundation\Http\Middleware\VerifyCsrfToke

n->handle()

21 /app/www/vendor/laravel/framework/src/Illuminate/View/Middleware/ShareErrorsFromSession.php(49): Illuminate\Pipeline\Pipeline->Illu

minate\Pipeline\{closure}()

22 /app/www/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\View\Middleware\ShareErrorsFromSession->ha

ndle()

23 /app/www/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(121): Illuminate\Pipeline\Pipeline->Illuminate

\Pipeline\{closure}()

24 /app/www/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(64): Illuminate\Session\Middleware\StartSessi

on->handleStatefulRequest()

25 /app/www/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\Session\Middleware\StartSession->handle()

26 /app/www/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php(37): Illuminate\Pipeline\Pipeline

->Illuminate\Pipeline\{closure}()

27 /app/www/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\Cookie\Middleware\AddQueuedCookiesToRespon

se->handle()

28 /app/www/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php(67): Illuminate\Pipeline\Pipeline->Illuminate

\Pipeline\{closure}()

29 /app/www/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\Cookie\Middleware\EncryptCookies->handle()

30 /app/www/app/Http/Middleware/ApplyCspRules.php(33): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()

31 /app/www/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): BookStack\Http\Middleware\ApplyCspRules->handle()

32 /app/www/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(116): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{c

losure}()

33 /app/www/vendor/laravel/framework/src/Illuminate/Routing/Router.php(797): Illuminate\Pipeline\Pipeline->then()

34 /app/www/vendor/laravel/framework/src/Illuminate/Routing/Router.php(776): Illuminate\Routing\Router->runRouteWithinStack()

35 /app/www/vendor/laravel/framework/src/Illuminate/Routing/Router.php(740): Illuminate\Routing\Router->runRoute()

36 /app/www/vendor/laravel/framework/src/Illuminate/Routing/Router.php(729): Illuminate\Routing\Router->dispatchToRoute()

37 /app/www/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(190): Illuminate\Routing\Router->dispatch()

38 /app/www/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(141): Illuminate\Foundation\Http\Kernel->Illuminate\Founda

tion\Http\{closure}()

39 /app/www/vendor/laravel/framework/src/Illuminate/Http/Middleware/TrustProxies.php(39): Illuminate\Pipeline\Pipeline->Illuminate\Pi

peline\{closure}()

40 /app/www/app/Http/Middleware/TrustProxies.php(41): Illuminate\Http\Middleware\TrustProxies->handle()

41 /app/www/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): BookStack\Http\Middleware\TrustProxies->handle()

42 /app/www/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\Pipeline\Pipeline

->Illuminate\Pipeline\{closure}()

43 /app/www/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php(40): Illuminate\Foundation\Http\Middle

ware\TransformsRequest->handle()

Environment

- OS: ubuntu 
uname -r -> Linux brix 6.2.0-33-generic #33-Ubuntu SMP PREEMPT_DYNAMIC Tue Sep  5 14:49:19 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

- How docker service was installed:
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

# Add the repository to Apt sources:
echo \
  "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo usermod -aG docker $USER

CPU architecture

x86-64

Docker creation

version: "2"
services:
  wiki:
    image: lscr.io/linuxserver/bookstack
    container_name: wiki
    networks:
      - wiki_net
    environment:
      - PUID=1000
      - PGID=1000
      - APP_URL=http://192.168.178.100:6875
      - DB_HOST=wiki_db
      - DB_PORT=3306
      - DB_USER=bookstack
      - DB_PASS=xxx
      - DB_DATABASE=bookstackapp
    volumes:
      - wiki_data:/config
    ports:
      - 6875:80
    restart: unless-stopped
    depends_on:
      - wiki_db
  wiki_db:
    image: lscr.io/linuxserver/mariadb
    container_name: wiki_db
    networks:
      - wiki_net
    environment:
      - PUID=1000
      - PGID=1000
      - MYSQL_ROOT_PASSWORD=xxx
      - TZ=Europe/Berlin
      - MYSQL_DATABASE=bookstackapp
      - MYSQL_USER=bookstack
      - MYSQL_PASSWORD=xxx
    volumes:
      - wiki_db_data:/config
    restart: unless-stopped

volumes:
  wiki_data:
  wiki_db_data:

networks:
  wiki_net:

Container logs

nothing special in the logs (error shown before)

Maybe a hint how I got this working:
I did a 
chown abc:users .
in
/app/www/public/uploads
since this folder belongs to root

after this I could upload stuff. But there was a new file structure created (new folder 'images')

root@a36cf9efd6bf:/app/www/public/uploads# ll
total 12
drwxrwxr-x 1 abc  users  6 Oct  2 22:59 .
drwxrwxr-x 1 root root   3 Oct  2 18:23 ..
drwxr-xr-x 4 abc  users  4 Oct  2 23:01 images
lrwxrwxrwx 1 root root  19 Oct  2 22:22 uploads -> /config/www/uploads

For me it looks like that the symlink 'uploads -> /config/www/uploads' is one level to deep

If I follow the link I land at:
root@a36cf9efd6bf:/app/www/public/uploads/uploads# 

I'll try to remove the symlink and set it directly in /app/www/public/ (without the filter uploads present)
github-actions[bot] commented 9 months ago

Thanks for opening your first issue here! Be sure to follow the relevant issue templates, or risk having this issue marked as invalid.

HC-Pinky commented 9 months ago

Update:

I redid my hole docker setup and now this is working properly

root@201adeeb1957:/app/www/public# ll
total 135
drwxrwxr-x  4 root root    19 Oct  3 03:45 .
drwxr-xr-x 14 root root    34 Oct  3 03:45 ..
-rw-rw-r--  1 root root   603 Sep 15 12:49 .htaccess
-rw-rw-r--  1 root root  5672 Sep 15 12:49 book_default_cover.png
drwxrwxr-x  2 root root     8 Oct  2 18:23 dist
-rw-rw-r--  1 root root  3538 Sep 15 12:49 icon-128.png
-rw-rw-r--  1 root root  6167 Sep 15 12:49 icon-180.png
-rw-rw-r--  1 root root  1338 Sep 15 12:49 icon-32.png
-rw-rw-r--  1 root root  1951 Sep 15 12:49 icon-64.png
-rw-rw-r--  1 root root 10933 Sep 15 12:49 icon.ico
-rw-rw-r--  1 root root  6900 Sep 15 12:49 icon.png
-rw-rw-r--  1 root root  1782 Sep 15 12:49 index.php
drwxrwxr-x  3 root root     3 Oct  2 18:23 libs
-rw-rw-r--  1 root root 11098 Sep 15 12:49 loading.gif
-rw-rw-r--  1 root root  2096 Sep 15 12:49 loading_error.png
-rw-rw-r--  1 root root  5415 Sep 15 12:49 logo.png
lrwxrwxrwx  1 root root    19 Oct  3 03:45 uploads -> /config/www/uploads
-rw-rw-r--  1 root root  7405 Sep 15 12:49 user_avatar.png
-rw-rw-r--  1 root root  1193 Sep 15 12:49 web.config

symlinks are set correctly and the app is able to store stuff

Took me quite a while to figure this out. When I tried to redo the symlink myself I was not able to rmdir or rm -rf the uploads folder. This is very odd and quiete a rar topic on the internet...

I finally got a hint deep in a forum that the docker overlayfs might cause trouble here. My system uses zfs for everything (including root partition). I followed https://docs.docker.com/storage/storagedriver/zfs-driver/ to use the propper zfs driver and then this worked!

My other system where I migrate from worked fine and there was the zfs driver already in place.

Maybe it is worth a hint on the README to use the zfs driver if /var/lib/docker runs that