Cannot update system because pdf is not writable

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…