InvoiceShelf
Open source invoicing solution for individuals and businesses
Alternative to: freshbooks, invoice ninja, zoho invoice
3.0.0-alpha.8
2026-09-25Eighth public alpha of InvoiceShelf 3.0. It closes security issues in the mail, file disk and installer settings, fixes foreign-currency documents on PostgreSQL, and makes the Docker image ready for hosting: it runs on a read-only filesystem, gives the customer portal a host of its own and carries its PDF fonts.
⚠️ Pre-release, not for production. Back up your database before upgrading and use this release for evaluation and testing only.
Security
- A company owner could make the server connect to internal addresses through the company mail settings, with an SMTP host or mail URL on a private or reserved network, and use the test mail to probe them. A company mail server must now be a public host. The super administrator keeps the private network, and
MAIL_ALLOWED_PRIVATE_HOSTSnames internal relays any owner may use. GHSA-r234 (#871) - Any request could pick the file disk the app wrote to for its whole lifetime with a
file_disk_idparameter. Only the backup screens choose a disk now, for themselves. (#869) - A file disk’s saved credentials could set the storage driver and other internal options. The driver comes only from the disk’s type, which must be one InvoiceShelf supports, and S3-compatible disks are checked like S3 ones. (#870)
- The installer’s wizard token never expired. It now lasts two hours (
INSTALL_WIZARD_TOKEN_TTL, in minutes). (#872)
Highlights
- Runs on a read-only filesystem. With
INVOICESHELF_DOTENV=falsethe Docker image starts without a.envand takes every setting,APP_KEYincluded, from the environment. Onlystorage/and a few temporary mounts need to be writable, and CI now boots the image that way on every change to it. (#879) - The customer portal on a host of its own.
CUSTOMER_PORTAL_URL(andCUSTOMER_PORTAL_HOSTSfor more than one) moves every link sent to a customer there. That host serves the portal and public documents only, and customer pages opened on the app host move to it. (#881) - Managed mode for hosting providers.
INVOICESHELF_MANAGED=truehides the storage, backup, PDF, server mail and module install settings from the install’s owner, who then brings only their own SMTP server, and sends platform mail from the platform address with the user as Reply-To. (#875, #878) - PDF fonts built into an image.
php artisan pdf:fonts:install --all --path=...downloads the language font packages ahead of time,PDF_FONTS_PATHpoints at them andPDF_FONTS_DOWNLOAD=falsestops downloads while the app runs. Every font now comes from a fixed release or commit and is checked against its SHA-256. (#882) - Headless installs can give the administrator a random password and email them a link to set their own (
--admin-password-random --send-welcome), read the password from a file (INSTALL_ADMIN_PASSWORD_FILE), and set the date format and fiscal year. (#876)
Improvements and fixes
- Owners can add a member with a password, next to Invite member on the Members page, for a server that sends no mail or a colleague who should not wait for an invitation. (#859, #883)
- Building a company role takes a few clicks: View Only next to Select All and None, and All, View and None on each module, with the permissions they depend on ticked for you. Select All no longer adds every permission twice. (#860, #884)
- On PostgreSQL, saving an estimate, invoice or expense in a foreign currency failed whenever the exchange rate had decimals, with
invalid input syntax for type bigint. Amounts converted to the company currency are now rounded to whole cents before they are stored, everywhere they are written: documents, lines, taxes, copies, recurring invoices, payments and balances. The exchange rate keeps its decimals. (#798, #862, #864) - The exchange-rate update for existing documents, which runs after the company currency changes, took each document’s discount from its subtotal and converted taxes twice. It now converts each amount from its own value. (#862)
- Installing or removing a module from the marketplace could fail at the last step, while clearing caches, after the module had been downloaded and verified. (#858)
- The customer picker on invoice, estimate and recurring invoice forms logged an error in the browser console, and keyboard focus did not follow a pick or a clear: it now moves to the customer card after a pick and back to the picker after Deselect. (#865)
- Overdue invoices and expired estimates are flagged even when the server was down at midnight:
invoiceshelf:catch-upruns the day’s checks once if they have not run, hourly and when the Docker image starts. (#877, #879) - SQLite waits up to five seconds for a lock instead of failing with “database is locked” (
DB_BUSY_TIMEOUT), andDB_JOURNAL_MODEandDB_SYNCHRONOUScan turn on WAL. (#874) - Saving company SMTP settings with the optional fields left blank no longer fails. (#871)
- The company mail settings no longer fail to load their list of mail drivers for a company owner who is not the super administrator. (#878)
- The Settings link in the administration area no longer leads to a missing page. (#875)
- A PDF font package that cannot be downloaded no longer stops the document: it is logged and the PDF uses Noto Sans. (#882)
- Sign-in pages, public documents and document emails take their “Powered by” line from one setting (
INVOICESHELF_POWERED_BY,_NAME,_URL), and the account menus link to the source code of the running version (INVOICESHELF_SOURCE_URL). (#880)
Upgrade notes
- Documents saved before this release keep the company-currency amounts they were stored with. Saving a document again recalculates them.
- Company mail on an internal address: a company mail server on a private address that an owner who is not the super administrator saved before this release keeps sending, but its test mail is refused and saving its settings asks for a public host. List the relay in
MAIL_ALLOWED_PRIVATE_HOSTSto keep it. - Docker: the image now sets
CONTAINERIZED=truein its environment, runsinvoiceshelf:catch-upwhen it starts, and refuses to start on the key InvoiceShelf used to ship whenINVOICESHELF_MANAGEDis on or there is no.env.
Docker: invoiceshelf/invoiceshelf:3.0.0-alpha.8 or ghcr.io/invoiceshelf/invoiceshelf:3.0.0-alpha.8 (also :next).