Cannot update system because pdf is not writable

Thanks @Lionboy!

My environment is Debian 9 w/ ISPConfig. I tried
find ./ -type d -exec chmod 755 {} ;

find: missing argument to `-exec’
Try ‘find --help’ for more information.

Above does not work in my environment.

You want to do

cd /path/to/invoiceninja
chown -R web1:www-data public/storage/hzpv21u1nngmblvhtuzgn9sam9lpldbv
chown -R web1:www-data vendor/beganovich/snappdf/versions/931145-Linux_x64
chown -R web1:www-data error
chown -R web1:www-data bootstrap/cache

“www-data” should be replaced by whatever group name your /path/to/invoiceninja uses. You can do

/bin/ls -la

to find the group name. Chances are its also “web1”. If you repeat the find command after that, it should come back with no output.

The previously suggested “find ./ -type d -exec chmod 755 {} ;” is not going to cut it, because

  1. it only searches for directories, not ordinary files ("-type d")
  2. it changes the file permission (calling “chmod”) instead of the ownership (should call “chown”)

The “missing argument” error you see probably occurs just because the semicolon is a special characters to your shell and needs to be escaped by a backslash. Also note, the space between the braces a the escaped semicolon is required. If you really want to do it using find, the correct commands should be something like

find . \( ! -perm -644 \) -exec chmod go=u-w {} \;
find . \( ! -user web1 \) -exec chown web1 {} \;
find . \( ! -group www-data \) -exec chgrp www-data {} \;

(The “go=u-w” argument to chown means “set the ‘group’ and ‘other’ permissions to the same value as the ‘user’ permission, but without ‘write’”.)

PS: I really recommend getting a book on UNIX and its basic commands if you want to self-host. “man find”, “man chown”, and “man chmod” are also your friends. You may also want to “echo $SHELL” and then “man sh”, “man bash”, “man ksh”, or whatever other shell the echo-command returns.

@anristudio, have you managed to resolve your permissions issue?

@xoo thank you very much, i appreciate it.

After I did

chown -R web1:client1 public/storage/hzpv21u1nngmblvhtuzgn9sam9lpldbv
chown -R web1:client1 vendor/beganovich/snappdf/versions/931145-Linux_x64
chown -R web1:client1 error
chown -R web1:client1 bootstrap/cache

I issued
find . ( ! -user web1 -o ! -perm -644 ) -ls
came back with no output

I also issued

find . ( ! -perm -644 ) -exec chmod go=u-w {} ;
find . ( ! -user web1 ) -exec chown web1 {} ;
find . ( ! -group client1 ) -exec chgrp client1 {} ;

also came back with no output

Update from current version v5.3.15 to latest version v5.5.38 still does not work.

/storage/logs/laravel.log

[2022-11-12 23:35:23] production.ERROR: SplFileInfo::isFile(): open_basedir restriction in effect. File(/var/www/clients/client1/web1/web/billing2/…) is not within the allowed path(s): (/var/www/clients/client1/web1/web/billing2:/var/www/clients/client1/web1/private:/var/www/clients/client1/web1/tmp:/var/www/billing2.mydomain.com/web/billing2:/srv/www/billing2.mydomain.com/web/billing2:/usr/share/php5:/usr/share/php:/tmp:/usr/share/phpmyadmin:/etc/phpmyadmin:/var/lib/phpmyadmin:/dev/random:/dev/urandom:/usr/local/bin/phantomjs:/usr/share/php) {“userId”:1,“exception”:"[object] (RuntimeException(code: 0): SplFileInfo::isFile(): open_basedir restriction in effect. File(/var/www/clients/client1/web1/web/billing2/…) is not within the allowed path(s): (/var/www/clients/client1/web1/web/billing2:/var/www/clients/client1/web1/private:/var/www/clients/client1/web1/tmp:/var/www/billing2.mydomain.com/web/billing2:/srv/www/billing2.mydomain.com/web/billing2:/usr/share/php5:/usr/share/php:/tmp:/usr/share/phpmyadmin:/etc/phpmyadmin:/var/lib/phpmyadmin:/dev/random:/dev/urandom:/usr/local/bin/phantomjs:/usr/share/php) at /var/www/clients/client1/web1/web/billing2/vendor/codedge/laravel-selfupdater/src/helpers.php:36)
[stacktrace]
#0 /var/www/clients/client1/web1/web/billing2/vendor/codedge/laravel-selfupdater/src/helpers.php(36): SplFileInfo->isFile()
#1 /var/www/clients/client1/web1/web/billing2/vendor/codedge/laravel-selfupdater/src/Models/UpdateExecutor.php(55): checkPermissions()
#2 /var/www/clients/client1/web1/web/billing2/vendor/codedge/laravel-selfupdater/src/SourceRepository.php(65): Codedge\Updater\Models\UpdateExecutor->run()
#3 /var/www/clients/client1/web1/web/billing2/app/Http/Controllers/SelfUpdateController.php(73): Codedge\Updater\SourceRepository->update()
#4 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Routing/Controller.php(54): App\Http\Controllers\SelfUpdateController->update()
#5 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): Illuminate\Routing\Controller->callAction()
#6 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Routing/Route.php(261): Illuminate\Routing\ControllerDispatcher->dispatch()
#7 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Routing/Route.php(204): Illuminate\Routing\Route->runController()
#8 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Routing/Router.php(695): Illuminate\Routing\Route->run()
#9 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(128): Illuminate\Routing\Router->Illuminate\Routing\{closure}()
#10 /var/www/clients/client1/web1/web/billing2/app/Http/Middleware/QueryLogging.php(40): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#11 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): App\Http\Middleware\QueryLogging->handle()
#12 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php(50): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#13 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Routing\Middleware\SubstituteBindings->handle()
#14 /var/www/clients/client1/web1/web/billing2/app/Http/Middleware/Locale.php(34): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#15 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): App\Http\Middleware\Locale->handle()
#16 /var/www/clients/client1/web1/web/billing2/app/Http/Middleware/PasswordProtection.php(102): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#17 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): App\Http\Middleware\PasswordProtection->handle()
#18 /var/www/clients/client1/web1/web/billing2/app/Http/Middleware/TokenAuth.php(80): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#19 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): App\Http\Middleware\TokenAuth->handle()
#20 /var/www/clients/client1/web1/web/billing2/app/Http/Middleware/SetDb.php(41): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#21 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): App\Http\Middleware\SetDb->handle()
#22 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php(127): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#23 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php(63): Illuminate\Routing\Middleware\ThrottleRequests->handleRequest()
#24 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Routing\Middleware\ThrottleRequests->handle()
#25 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(103): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#26 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Routing/Router.php(697): Illuminate\Pipeline\Pipeline->then()
#27 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Routing/Router.php(672): Illuminate\Routing\Router->runRouteWithinStack()
#28 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Routing/Router.php(636): Illuminate\Routing\Router->runRoute()
#29 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Routing/Router.php(625): Illuminate\Routing\Router->dispatchToRoute()
#30 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(166): Illuminate\Routing\Router->dispatch()
#31 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(128): Illuminate\Foundation\Http\Kernel->Illuminate\Foundation\Http\{closure}()
#32 /var/www/clients/client1/web1/web/billing2/vendor/sentry/sentry-laravel/src/Sentry/Laravel/Http/SetRequestIpMiddleware.php(55): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#33 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Sentry\Laravel\Http\SetRequestIpMiddleware->handle()
#34 /var/www/clients/client1/web1/web/billing2/vendor/sentry/sentry-laravel/src/Sentry/Laravel/Http/SetRequestMiddleware.php(52): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#35 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Sentry\Laravel\Http\SetRequestMiddleware->handle()
#36 /var/www/clients/client1/web1/web/billing2/app/Http/Middleware/Cors.php(25): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#37 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): App\Http\Middleware\Cors->handle()
#38 /var/www/clients/client1/web1/web/billing2/vendor/fideloper/proxy/src/TrustProxies.php(57): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#39 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Fideloper\Proxy\TrustProxies->handle()
#40 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#41 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ConvertEmptyStringsToNull.php(31): Illuminate\Foundation\Http\Middleware\TransformsRequest->handle()
#42 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull->handle()
#43 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#44 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php(40): Illuminate\Foundation\Http\Middleware\TransformsRequest->handle()
#45 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Foundation\Http\Middleware\TrimStrings->handle()
#46 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php(27): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#47 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Foundation\Http\Middleware\ValidatePostSize->handle()
#48 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php(86): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#49 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance->handle()
#50 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(103): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#51 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(141): Illuminate\Pipeline\Pipeline->then()
#52 /var/www/clients/client1/web1/web/billing2/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\Foundation\Http\Kernel->sendRequestThroughRouter()
#53 /var/www/clients/client1/web1/web/billing2/public/index.php(57): Illuminate\Foundation\Http\Kernel->handle()
#54 {main}
"}

@za_admin-Frontend not yet

User=web1, Group=client1, has permissions/ownership/access to root folder of the same website (and all files, folders & subfolders)

I have cron job setup under same website.
cd /var/www/clients/client1/web1/web/billing2/ && /usr/bin/php7.4 artisan schedule:run >> /dev/null 2>&1

@david any ideas/suggestions how to fix this?

Most likely your cron user is being run a root, you’ll want the crons to run as the webuser to ensure permissions remain correct.

@david thank you!
When I click on UPDATE NOW this is what I get: “Cannot update system, config.php is not writable” it’s different error from initial one.

most likely you may have run

php artisan optimize

from the command line as your own user, you’ll need to chown the boostrap/ directory to the webuser.

I ran php artisan optimize

Configuration cache cleared!
Configuration cached successfully!
Route cache cleared!
Routes cached successfully!
Files cached successfully!

I also chown the boostrap/ folder as my webuser:
chown -R web1:client1 /var/www/clients/client1/web1/web/billing2/bootstrap

ls -la
drwxr-xr-x 3 web1 client1 4096 Sep 17 2021 bootstrap

Same error as in last post.

The system does a recursive file check, when you see this issue, it means the system does not have write access to the file mentioned.

2 files didn’t have write access, I gave WRITE access to 2 files as well as entire folders bootstrap & cache

chmod -R 777 /var/www/clients/client1/web1/web/billing2/bootstrap/cache/config.php
chmod -R 777 /var/www/clients/client1/web1/web/billing2/bootstrap/cache/routes-v7.php

chmod -R 777 /var/www/clients/client1/web1/web/billing2/bootstrap/
chmod -R 777 /var/www/clients/client1/web1/web/billing2/bootstrap/cache/

now when I click on UPDATE NOW this is what I get: Server Error without any details.

from the LOG
/storage/logs/laravel.log

[2022-11-13 16:22:59] production.ERROR: SplFileInfo::isFile(): open_basedir restriction in effect. File(/var/www/clients/client1/web1/web/billing2/…) is not within the allowed path(s): (/var/www/clients/client1/web1/web/billing2:/var/www/clients/client1/web1/private:/var/www/clients/client1/web1/tmp:/var/www/billing2.mydomain.com/web/billing2:/srv/www/billing2.mydomain.com/web/billing2:/usr/share/php5:/usr/share/php:/tmp:/usr/share/phpmyadmin:/etc/phpmyadmin:/var/lib/phpmyadmin:/dev/random:/dev/urandom:/usr/local/bin/phantomjs:/usr/share/php) {“userId”:1,“exception”:"[object] (RuntimeException(code: 0): SplFileInfo::isFile(): open_basedir restriction in effect. File(/var/www/clients/client1/web1/web/billing2/…) is not within the allowed path(s): (/var/www/clients/client1/web1/web/billing2:/var/www/clients/client1/web1/private:/var/www/clients/client1/web1/tmp:/var/www/billing2.mydomain.com/web/billing2:/srv/www/billing2.mydomain.com/web/billing2:/usr/share/php5:/usr/share/php:/tmp:/usr/share/phpmyadmin:/etc/phpmyadmin:/var/lib/phpmyadmin:/dev/random:/dev/urandom:/usr/local/bin/phantomjs:/usr/share/php) at /var/www/clients/client1/web1/web/billing2/vendor/codedge/laravel-selfupdater/src/helpers.php:36)
[stacktrace]

Hi @anristudio

Maybe something with your open_basedir config is wrong.

From the InvoiceNinja Docs:

file_exists(): open_basedir restriction in effect

If you aren’t able to adjust the open_basedir restrictions the following steps may help:

  1. Delete bootstrap/cache/config.php
  2. Delete all log files in storage/logs

Another thing I ran into, was the .htaccess-Files in root folder and in the /public folder. This is necessary if you are on a subdomain like business.domain.com.

My root .htaccess looks this way:

The .htaccess in the /public folder:

Maybe this hints help you…

P.S. I need to adjust the .htaccess files after every Update since both file are overwritten by setup routine…

1 Like

Thanks @checkitsedo
I tried your suggestion with .htaccess without any luck
I also try deleting files you mentioned same issues

I run my own hosting, I have access to configure “open_base restrictions”. In my environment, root path to InvoiceNinja is already added to open_base restrictions. Am i missing something, do I need to add additional path to “open_base restrictions”?

open_basedir restriction in effect. File(/var/www/clients/client1/web1/web/billing2/…

@anristudio

Where does the domain https://billing2.domain.com/ points to?

In my Environment i use also a subdomain. The InvoiceNinja Path is /var/www/virtual/checkit/invoiceninja. Then I have a domain shortcut business.mydomain.com which points to /var/www/virtual/checkit/invoiceninja/public

I set the APP_URL in the .env to https://business.mydomain.com (without /public and without / at the end)…

Whats happened if you set open_basedir to none? This is surely not a solution, but could help finding reason why it doesn‘t work…

I\

https://billing2.domain.com/ is a subdomain, same URL is set in .env

If I set open_basedir = none I get Cannot update system because .htaccess is not writable?

I change both .htaccess files in root & public folder to 777 still same error

Ok, i don’t know, if it helps something, but I had always troubles to update Invoiceninja… So, this is my (working) workflow:

  1. Go back to the last working version (without this I could not get a failed update to work afterwards)

    • Delete the invoiceninja folder completely.

    • restore from backup
      rsync --verbose --recursive --links --perms --times --hard-links --acls --xattrs /path/to/backup/invoiceninja/ /var/www/virtual/checkit/invoiceninja/

    • restore folder permissions
      restorecon -R /var/www/virtual/checkit/invoiceninja/

    • start invoiceninja queue (if available)

    • fix .htaccess (complete files below)
      → /var/www/virtual/checkit/invoiceninja/.htaccess
      → /var/www/virtual/checkit/invoiceninja/public/.htaccess

    • Ensure that Invoiceninja is working fine

  2. create a backup of the database
    mysql checkit_invoiceninja < /var/www/virtual/checkit/cechkit_invoiceninja.sql

  3. update to latest version
    → git pull
    → git checkout v5-stable
    → composer install
    → php artisan ninja:post-update

  4. correct files
    → /var/www/virtual/checkit/invoiceninja/.htaccess
    → /var/www/virtual/checkit/invoiceninja/public/.htaccess

  5. Invoiceninja migrations (if neccessary)
    → php artisan migrate --force

  6. call Invoiceninja
    → clear browser cache
    https://business.mydomain.com/update?secret=secret

/var/www/virtual/checkit/invoiceninja/.htaccess

<IfModule mod_rewrite.c>
  # Redirect HTTP to HTTPS:
  RewriteCond %{ENV:HTTPS} !=on
  RewriteRule ^(.*) https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
  
  # Make InvoiceNinja work in subdomains:
  RewriteBase /
  RewriteRule ^(.*)$ public/$1 [L]
  
  RewriteRule "^.env" - [F,L]
#  RewriteRule "^storage" - [F,L]
  RewriteRule ^(.well-known)($|/) - [L]
  
  RewriteRule ^(.*)$ public/$1 [L]
</IfModule>

# https://github.com/h5bp/server-configs-apache/blob/master/dist/.htaccess


# ######################################################################
# # INTERNET EXPLORER                                                  #
# ######################################################################

# ----------------------------------------------------------------------
# | Iframes cookies                                                    |
# ----------------------------------------------------------------------

# Allow cookies to be set from iframes in Internet Explorer.
#
# https://msdn.microsoft.com/en-us/library/ms537343.aspx
# http://www.w3.org/TR/2000/CR-P3P-20001215/

<IfModule mod_headers.c>
    Header set P3P "policyref=\"/w3c/p3p.xml\", CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\""
</IfModule>


# ######################################################################
# # MEDIA TYPES AND CHARACTER ENCODINGS                                #
# ######################################################################

# ----------------------------------------------------------------------
# | Character encodings                                                |
# ----------------------------------------------------------------------

# Serve all resources labeled as `text/html` or `text/plain`
# with the media type `charset` parameter set to `UTF-8`.
#
# https://httpd.apache.org/docs/current/mod/core.html#adddefaultcharset

AddDefaultCharset utf-8

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

# Serve the following file types with the media type `charset`
# parameter set to `UTF-8`.
#
# https://httpd.apache.org/docs/current/mod/mod_mime.html#addcharset

<IfModule mod_mime.c>
    AddCharset utf-8 .atom \
                     .bbaw \
                     .css \
                     .geojson \
                     .js \
                     .json \
                     .jsonld \
                     .manifest \
                     .rdf \
                     .rss \
                     .topojson \
                     .vtt \
                     .webapp \
                     .webmanifest \
                     .xloc \
                     .xml
</IfModule>


# ######################################################################
# # WEB PERFORMANCE                                                    #
# ######################################################################

# ----------------------------------------------------------------------
# | Compression                                                        |
# ----------------------------------------------------------------------

<IfModule mod_deflate.c>

    # Force compression for mangled headers.
    # https://developer.yahoo.com/blogs/ydn/pushing-beyond-gzipping-25601.html

    <IfModule mod_setenvif.c>
        <IfModule mod_headers.c>
            SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding
            RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding
        </IfModule>
    </IfModule>

    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    # Map certain file types to the specified encoding type in order to
    # make Apache serve them with the appropriate `Content-Encoding` HTTP
    # response header (this will NOT make Apache compress them!).

    # If the following file types wouldn't be served without the appropriate
    # `Content-Enable` HTTP response header, client applications (e.g.:
    # browsers) wouldn't know that they first need to uncompress the response,
    # and thus, wouldn't be able to understand the content.

    # http://httpd.apache.org/docs/current/mod/mod_mime.html#addencoding

    <IfModule mod_mime.c>
        AddEncoding gzip              svgz
    </IfModule>

    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    # Compress all output labeled with one of the following media types.

    # IMPORTANT: For Apache versions below 2.3.7 you don't need to enable
    # `mod_filter` and can remove the `<IfModule mod_filter.c>` & `</IfModule>`
    # lines as `AddOutputFilterByType` is still in the core directives.

    <IfModule mod_filter.c>
        AddOutputFilterByType DEFLATE "application/atom+xml" \
                                      "application/javascript" \
                                      "application/json" \
                                      "application/ld+json" \
                                      "application/manifest+json" \
                                      "application/rdf+xml" \
                                      "application/rss+xml" \
                                      "application/schema+json" \
                                      "application/vnd.geo+json" \
                                      "application/vnd.ms-fontobject" \
                                      "application/x-font-ttf" \
                                      "application/x-web-app-manifest+json" \
                                      "application/xhtml+xml" \
                                      "application/xml" \
                                      "font/opentype" \
                                      "image/svg+xml" \
                                      "image/x-icon" \
                                      "text/cache-manifest" \
                                      "text/css" \
                                      "text/html" \
                                      "text/javascript" \
                                      "text/plain" \
                                      "text/vtt" \
                                      "text/x-component" \
                                      "text/xml"
    </IfModule>

</IfModule>

/var/www/virtual/checkit/invoiceninja/public/.htaccess

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews -Indexes
    </IfModule>

    RewriteEngine On
	
	# Make InvoiceNinja work with subdomains:
	# If you want to access InvoiceNinja via a subdomain and
	# this rule is missing the browser will see a `500 internal server error`.
	RewriteBase /

    # Handle Authorization Header
    RewriteCond %{HTTP:Authorization} .
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

    # Redirect Trailing Slashes If Not A Folder...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} (.+)/$
    RewriteRule ^ %1 [L,R=301]

    # Handle Front Controller...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]
</IfModule>

<IfModule mod_headers.c>
    # Blocks Search Engine Indexing
    Header set X-Robots-Tag "noindex, nofollow"

    # Prevents PDF File Caching
    <FilesMatch ".pdf$">
        Header set Cache-Control no-store
    </FilesMatch>
</IfModule>

/var/www/virtual/checkit/invoiceninja/.env (excerpt)

APP_URL="https://business.mydomain.com" //important: no slash at the end

BROADCAST_DRIVER=log
LOG_CHANNEL=stack
CACHE_DRIVER=file
QUEUE_CONNECTION=database
INTERNAL_QUEUE_ENABLED=false
SESSION_DRIVER=file
SESSION_LIFETIME=120

REQUIRE_HTTPS="true"

NINJA_ENVIRONMENT="selfhost"

#options - snappdf / phantom / hosted_ninja
PDF_GENERATOR=snappdf

UPDATE_SECRET=yoursecret

DELETE_PDF_DAYS=60
DELETE_BACKUP_DAYS=60

COMPOSER_AUTH='{"github-oauth": {"github.com": "${{ secrets.GITHUB_TOKEN }}"}}'

If this doesn’t work, I don’t know what else you could try. Maybe some others can help…

can you try

sudo chown -R webuser:webuser bootstrap/

And then attempt the upgrade again.

Hi David,

I did

chown -R web1:client1 /var/www/clients/client1/web1/web/billing2/bootstrap/
(billing2 is the folder where my Invoice Ninja is installed)

when I attempt to upgrade from v5.3.15 to v5.6.31 I still get “not writable”

[2023-08-21 13:25:39] production.INFO: Cannot update system because ee2f842aa7bb1f53edf3a2ed2c09a1807ffa6c90 is not writable

Anything else I could try?
Thanks in advance.

As a workaround you can manually copy over the latest release zip.