Unable to upload cover image #5147

Closed
opened 2026-02-05 09:44:08 +03:00 by OVERLORD · 10 comments
Owner

Originally created by @hastyeagle on GitHub (Jan 23, 2025).

Attempted Debugging

  • I have read the debugging page

Searched GitHub Issues

  • I have searched GitHub for the issue.

Describe the Scenario

When attempting to save a cover image to a shelf or book, for instance, after I click Save and then refresh the page to see the updated image, I see the following error:

nginx/error.log:
*62 open() "/usr/local/www/bookstack/public/uploads/images/cover_bookshelf/2025-01/thumbs-440-250/-image.jpg" failed (2: No such file or directory)

laravel.log doesn't show an error during this time, or during the "Save". When saving the change, I get the message saying "Shelf updated successfully". I enabled APP_DEBUG=true, but no error message is showing when attempting the change again.

The upload directories have the proper user:group (php-fpm runs as www). I ran the following to ensure this (changing barry to the correct username):

chown -R barry:www /usr/local/www/bookstack
chmod -R 755 /usr/local/www/bookstack
chmod -R 775 /usr/local/www/bookstack/storage /usr/local/www/bookstack/bootstrap/cache /usr/local/www/bookstack/public/uploads
chmod 640 /usr/local/www/bookstack/.env

I am able to attach files to pages just fine.

Exact BookStack Version

v24.12.1

Log Content

No response

Hosting Environment

FreeBSD 14.1
nginx v1.26.2
PHP-FPM v8.2.27

Originally created by @hastyeagle on GitHub (Jan 23, 2025). ### Attempted Debugging - [x] I have read the debugging page ### Searched GitHub Issues - [x] I have searched GitHub for the issue. ### Describe the Scenario When attempting to save a cover image to a shelf or book, for instance, after I click Save and then refresh the page to see the updated image, I see the following error: **nginx/error.log:** \*62 open() "/usr/local/www/bookstack/public/uploads/images/cover_bookshelf/2025-01/thumbs-440-250/<GUID>-image.jpg" failed (2: No such file or directory) `laravel.log` doesn't show an error during this time, or during the "Save". When saving the change, I get the message saying "Shelf updated successfully". I enabled `APP_DEBUG=true`, but no error message is showing when attempting the change again. The upload directories have the proper user:group (php-fpm runs as `www`). I ran the following to ensure this (changing barry to the correct username): ``` chown -R barry:www /usr/local/www/bookstack chmod -R 755 /usr/local/www/bookstack chmod -R 775 /usr/local/www/bookstack/storage /usr/local/www/bookstack/bootstrap/cache /usr/local/www/bookstack/public/uploads chmod 640 /usr/local/www/bookstack/.env ``` I am able to attach files to pages just fine. ### Exact BookStack Version v24.12.1 ### Log Content _No response_ ### Hosting Environment FreeBSD 14.1 nginx v1.26.2 PHP-FPM v8.2.27
OVERLORD added the 🐕 Support label 2026-02-05 09:44:08 +03:00
Author
Owner

@ssddanbrown commented on GitHub (Jan 23, 2025):

Hi @hastyeagle,

  • Does a /usr/local/www/bookstack/public/uploads/images/cover_bookshelf/2025-01/thumbs-440-250/ directory exist on your system?
  • If so, are there images within it?
  • If not, can you see your uploaded cover images in the parent directory?
  • Do other image uploads work (User profile or in-page images for example)?
@ssddanbrown commented on GitHub (Jan 23, 2025): Hi @hastyeagle, - Does a `/usr/local/www/bookstack/public/uploads/images/cover_bookshelf/2025-01/thumbs-440-250/` directory exist on your system? - If so, are there images within it? - If not, can you see your uploaded cover images in the parent directory? - Do other image uploads work (User profile or in-page images for example)?
Author
Owner

@hastyeagle commented on GitHub (Jan 23, 2025):

* Does a `/usr/local/www/bookstack/public/uploads/images/cover_bookshelf/2025-01/thumbs-440-250/` directory exist on your system?

No, it doesn't exist. Only /usr/local/www/bookstack/public/uploads exists. No sub-directories under it. I tried creating images and giving it the proper group and perms, but that didn't help, either.

Permissions on the directory are:
drwxrwxr-x 3 barry www 5 Jan 22 22:33 uploads

* If so, are there images within it?

No images anywhere in uploads.

* If not, can you see your uploaded cover images in the parent directory?

I'm not seeing the uploaded image anywhere under /usr/local/www/bookstack.

* Do other image uploads work (User profile or in-page images for example)?

User profile does the same thing:
*78 open() "/usr/local/www/bookstack/public/uploads/images/user/2025-01/thumbs-80-80/<GUID>-image.jpg" failed (2: No such file or directory)

Trying to upload an in-page image results in a similar error:
*78 open() "/usr/local/www/bookstack/public/uploads/images/gallery/2024-03/thumbs-150-150/<GUID>-image.png" failed (2: No such file or directory)

@hastyeagle commented on GitHub (Jan 23, 2025): > * Does a `/usr/local/www/bookstack/public/uploads/images/cover_bookshelf/2025-01/thumbs-440-250/` directory exist on your system? No, it doesn't exist. Only `/usr/local/www/bookstack/public/uploads` exists. No sub-directories under it. I tried creating `images` and giving it the proper group and perms, but that didn't help, either. Permissions on the directory are: `drwxrwxr-x 3 barry www 5 Jan 22 22:33 uploads` > * If so, are there images within it? No images anywhere in uploads. > * If not, can you see your uploaded cover images in the parent directory? I'm not seeing the uploaded image anywhere under /usr/local/www/bookstack. > * Do other image uploads work (User profile or in-page images for example)? User profile does the same thing: `*78 open() "/usr/local/www/bookstack/public/uploads/images/user/2025-01/thumbs-80-80/<GUID>-image.jpg" failed (2: No such file or directory)` Trying to upload an in-page image results in a similar error: `*78 open() "/usr/local/www/bookstack/public/uploads/images/gallery/2024-03/thumbs-150-150/<GUID>-image.png" failed (2: No such file or directory)`
Author
Owner

@ssddanbrown commented on GitHub (Jan 23, 2025):

@hastyeagle

  • Have you set any .env options for BookStack starting with STORAGE_?
  • Does anything get logged to a /usr/local/www/bookstack/storage/logs/laravel.log file on image upload?
  • What user is nginx running as?

Also, that last log message your shared is odd as it's reflecting an image from last year.
Is this a migrated/upgraded instance where images previously worked?

@ssddanbrown commented on GitHub (Jan 23, 2025): @hastyeagle - Have you set any `.env` options for BookStack starting with `STORAGE_`? - Does anything get logged to a `/usr/local/www/bookstack/storage/logs/laravel.log` file on image upload? - What user is nginx running as? Also, that last log message your shared is odd as it's reflecting an image from last year. Is this a migrated/upgraded instance where images previously worked?
Author
Owner

@hastyeagle commented on GitHub (Jan 23, 2025):

Have you set any .env options for BookStack starting with STORAGE_?

I've got STORAGE_TYPE=local_secure set.

Does anything get logged to a /usr/local/www/bookstack/storage/logs/laravel.log file on image upload?

Nothing logged there.

What user is nginx running as?

nginx is running as www, as is php-fpm.

Also, that last log message your shared is odd as it's reflecting an image from last year.
Is this a migrated/upgraded instance where images previously worked?

Honestly, I don't think I ever tried attaching an image to a page or avatar/cover image. Someone tried yesterday and said they couldn't, so I started looking into it.

I think that error was for an image that I must have tried attaching last March (and just picked the wrong error log thinking it was the most recent). I can't remember ;) I just tried again, and it throws 3 errors when I go to the image picker, but since all 3 images are "X"s (see below), they throw an error in nginx logs.

Image

The error for the image I tried uploading is similar:
*112 open() "/usr/local/www/bookstack/public/uploads/images/gallery/2025-01/thumbs-150-150/<GUID>-image.jpg" failed (2: No such file or directory)

@hastyeagle commented on GitHub (Jan 23, 2025): > Have you set any .env options for BookStack starting with STORAGE_? I've got `STORAGE_TYPE=local_secure` set. > Does anything get logged to a /usr/local/www/bookstack/storage/logs/laravel.log file on image upload? Nothing logged there. > What user is nginx running as? nginx is running as `www`, as is php-fpm. >Also, that last log message your shared is odd as it's reflecting an image from last year. Is this a migrated/upgraded instance where images previously worked? Honestly, I don't think I ever tried attaching an image to a page or avatar/cover image. Someone tried yesterday and said they couldn't, so I started looking into it. I think that error was for an image that I must have tried attaching last March (and just picked the wrong error log thinking it was the most recent). I can't remember ;) I just tried again, and it throws 3 errors when I go to the image picker, but since all 3 images are "X"s (see below), they throw an error in nginx logs. ![Image](https://github.com/user-attachments/assets/a3677fe1-16d2-4a18-ac90-7a61d0caf763) The error for the image I tried uploading is similar: `*112 open() "/usr/local/www/bookstack/public/uploads/images/gallery/2025-01/thumbs-150-150/<GUID>-image.jpg" failed (2: No such file or directory)`
Author
Owner

@hastyeagle commented on GitHub (Jan 23, 2025):

OK, I did find the images after all. It looks like they are being uploaded to /usr/local/www/bookstack/storage/uploads/images/cover_bookshelf for shelves, with other subdirectories under images for cover_book, gallery, and user.

So Bookstack is looking in the wrong place for them?

@hastyeagle commented on GitHub (Jan 23, 2025): OK, I did find the images after all. It looks like they are being uploaded to `/usr/local/www/bookstack/storage/uploads/images/cover_bookshelf` for shelves, with other subdirectories under `images` for cover_book, gallery, and user. So Bookstack is looking in the wrong place for them?
Author
Owner

@ssddanbrown commented on GitHub (Jan 23, 2025):

I've got STORAGE_TYPE=local_secure set.

Okay, that changes things significantly. In that case, I don't expect files to exist in the public/uploads folder.

  • Can your share your nginx config? (Of course can omit domains or other private info).

So Bookstack is looking in the wrong place for them?

No, that's from nginx. I don't expect nginx to find them but it should defer back to the app when not found, but that part is not happening. Most commonly it means there's nginx config set for these paths/files which means the request never reaches the app.

@ssddanbrown commented on GitHub (Jan 23, 2025): > I've got STORAGE_TYPE=local_secure set. Okay, that changes things significantly. In that case, I don't expect files to exist in the `public/uploads` folder. - Can your share your nginx config? (Of course can omit domains or other private info). > So Bookstack is looking in the wrong place for them? No, that's from nginx. I don't expect nginx to find them but it should defer back to the app when not found, but that part is not happening. Most commonly it means there's nginx config set for these paths/files which means the request never reaches the app.
Author
Owner

@hastyeagle commented on GitHub (Jan 23, 2025):

No, that's from nginx. I don't expect nginx to find them but it should defer back to the app when not found, but that part is not happening. Most commonly it means there's nginx config set for these paths/files which means the request never reaches the app.

Gotcha.

Here's my nginx config:

server {
    listen 443 ssl http2;
    server_name wiki.domain.com;

    root /usr/local/www/bookstack/public;
    index index.php index.html;

    # Use Mozilla's guidelines for SSL/TLS settings
    # https://mozilla.github.io/server-side-tls/ssl-config-generator/
    ssl_certificate /usr/local/etc/nginx/wiki.crt;
    ssl_certificate_key /usr/local/etc/nginx/wiki.key;

    ssl_session_cache shared:le_nginx_SSL:10m;
    ssl_session_timeout 1440m;
    ssl_session_tickets off;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers off;

    ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";

    proxy_set_header x-real-ip $remote_addr;
    proxy_set_header x-forwarded-for $proxy_add_x_forwarded_for;

    # Prevent nginx HTTP Server Detection
    server_tokens off;

    # set max upload size and increase upload timeout:
    client_max_body_size 32m;
    client_body_timeout 90s;
    fastcgi_buffers 64 4K;

    # Enable gzip but do not remove ETag headers
    gzip on;
    gzip_vary on;
    gzip_comp_level 4;
    gzip_min_length 256;
    gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
    gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/wasm application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;

    # HTTP response headers borrowed from Nextcloud `.htaccess`
    add_header Referrer-Policy                      "no-referrer"   always;
    add_header X-Content-Type-Options               "nosniff"       always;
    add_header X-Download-Options                   "noopen"        always;
    add_header X-Frame-Options                      "SAMEORIGIN"    always;
    add_header X-Permitted-Cross-Domain-Policies    "none"          always;
    add_header X-Robots-Tag                         "none"          always;
    add_header X-XSS-Protection                     "1; mode=block" always;

    # Ensure this block, which passes PHP files to the PHP process, is above the blocks
    # which handle static assets (as seen below). If this block is not declared first,
    # then Nginx will encounter an infinite rewriting loop when it prepends `/index.php`
    # to the URI, resulting in a HTTP 500 error response.
    location ~ \.php(?:$|/) {
        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        set $path_info $fastcgi_path_info;

        try_files $fastcgi_script_name =404;

        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $path_info;
        fastcgi_param HTTPS on;

        fastcgi_param modHeadersAvailable true;         # Avoid sending the security headers twice
        fastcgi_param front_controller_active true;     # Enable pretty urls
        fastcgi_pass php-handler;

        fastcgi_intercept_errors on;
        fastcgi_request_buffering off;

        fastcgi_max_temp_file_size 0;
    }

    # By default indexes are disabled on Nginx but if you have them enabled
    # add this to your BookStack server block
    location /uploads {
      autoindex off;
    }

    location / {
      try_files $uri $uri/ /index.php?$query_string;
    }
}
@hastyeagle commented on GitHub (Jan 23, 2025): >No, that's from nginx. I don't expect nginx to find them but it should defer back to the app when not found, but that part is not happening. Most commonly it means there's nginx config set for these paths/files which means the request never reaches the app. Gotcha. Here's my nginx config: ``` server { listen 443 ssl http2; server_name wiki.domain.com; root /usr/local/www/bookstack/public; index index.php index.html; # Use Mozilla's guidelines for SSL/TLS settings # https://mozilla.github.io/server-side-tls/ssl-config-generator/ ssl_certificate /usr/local/etc/nginx/wiki.crt; ssl_certificate_key /usr/local/etc/nginx/wiki.key; ssl_session_cache shared:le_nginx_SSL:10m; ssl_session_timeout 1440m; ssl_session_tickets off; ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers off; ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"; proxy_set_header x-real-ip $remote_addr; proxy_set_header x-forwarded-for $proxy_add_x_forwarded_for; # Prevent nginx HTTP Server Detection server_tokens off; # set max upload size and increase upload timeout: client_max_body_size 32m; client_body_timeout 90s; fastcgi_buffers 64 4K; # Enable gzip but do not remove ETag headers gzip on; gzip_vary on; gzip_comp_level 4; gzip_min_length 256; gzip_proxied expired no-cache no-store private no_last_modified no_etag auth; gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/wasm application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy; # HTTP response headers borrowed from Nextcloud `.htaccess` add_header Referrer-Policy "no-referrer" always; add_header X-Content-Type-Options "nosniff" always; add_header X-Download-Options "noopen" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Permitted-Cross-Domain-Policies "none" always; add_header X-Robots-Tag "none" always; add_header X-XSS-Protection "1; mode=block" always; # Ensure this block, which passes PHP files to the PHP process, is above the blocks # which handle static assets (as seen below). If this block is not declared first, # then Nginx will encounter an infinite rewriting loop when it prepends `/index.php` # to the URI, resulting in a HTTP 500 error response. location ~ \.php(?:$|/) { fastcgi_split_path_info ^(.+?\.php)(/.*)$; set $path_info $fastcgi_path_info; try_files $fastcgi_script_name =404; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $path_info; fastcgi_param HTTPS on; fastcgi_param modHeadersAvailable true; # Avoid sending the security headers twice fastcgi_param front_controller_active true; # Enable pretty urls fastcgi_pass php-handler; fastcgi_intercept_errors on; fastcgi_request_buffering off; fastcgi_max_temp_file_size 0; } # By default indexes are disabled on Nginx but if you have them enabled # add this to your BookStack server block location /uploads { autoindex off; } location / { try_files $uri $uri/ /index.php?$query_string; } } ```
Author
Owner

@ssddanbrown commented on GitHub (Jan 23, 2025):

@hastyeagle Try adding try_files $uri $uri/ /index.php?$query_string; within your location /uploads { block.

I think that would take precedence over the location / block so the request never calls back to the app for that path.

@ssddanbrown commented on GitHub (Jan 23, 2025): @hastyeagle Try adding `try_files $uri $uri/ /index.php?$query_string;` within your `location /uploads {` block. I think that would take precedence over the `location / ` block so the request never calls back to the app for that path.
Author
Owner

@hastyeagle commented on GitHub (Jan 23, 2025):

Bingo. Adding that try_files directive to location /uploads fixed it!

Thanks so much, Dan! And thanks for an awesome wiki!

@hastyeagle commented on GitHub (Jan 23, 2025): **Bingo**. Adding that `try_files` directive to `location /uploads` fixed it! Thanks so much, Dan! And thanks for an awesome wiki!
Author
Owner

@ssddanbrown commented on GitHub (Jan 25, 2025):

Glad to hear that got things working! I'll therefore close off this thread.

@ssddanbrown commented on GitHub (Jan 25, 2025): Glad to hear that got things working! I'll therefore close off this thread.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/BookStack#5147