invoiceninja-debian: an invoicing stack in one container image
Docker files for Invoice Ninja
At a glance
- What is it?
- The invoiceninja/dockerfiles repository builds the Invoice Ninja application into a Debian based image with NGINX, a built-in Chrome for PDF generation, the Saxon XSLT 2 engine and OPcache, and ships a compose file for a working deployment. It is convenient, and the README is frank about the three items still unfinished and the default credentials waiting for you.
- Who is it for?
- Adopt the invoiceninja-debian image when you want Invoice Ninja running under NGINX with PDF generation working out of the box, and when you are comfortable with the compose file's own opinion about the database and app wiring.
- Can I use it commercially?
- Yes, with conditions. GPL-2.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Go Template, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the Debian image actually bundles
This repository holds the Docker files for Invoice Ninja, and the README's headline image is the Debian build published as invoiceninja/invoiceninja-debian on Docker Hub.
The feature list is short and specific rather than generic. It includes NGINX webserver support, a built-in Chrome for PDF generation and other features, the Saxon XSLT 2 engine, OPcache, and multi language support. Each of those corresponds to a real capability in the product: Chrome is what renders invoices to PDF, Saxon is what handles the XSLT transformations, OPcache is what keeps PHP from recompiling on every request, and NGINX is the web server in front of the application.
Shipping Chrome inside the image is the decision with the largest consequences, in both directions. It is what makes PDF generation work without the operator wiring a headless browser into a separate container or installing one on the host. It is also what makes the image large. The README carries a Docker image size badge for exactly this reason, and an image that contains a browser is heavier to pull and to keep in a registry mirror than a plain PHP runtime.
The default branch is debian, and the repository also contains a charts/ directory, so the project covers both the image build and the Kubernetes chart side. The primary language recorded for the repository is Go Template, which is the templating used by Helm, and the release list shows image tags such as 5.13.49-d and 5.13.49-o, where the suffix tracks the Debian and other variants.
Environment variables live in .env, not in the compose file
The deployment starts with a clone of the debian branch:
git clone https://github.com/invoiceninja/dockerfiles.git -b debian
cd dockerfiles/debianThen the configuration step. The README explains that the environment variables are now defined in the `.env` file rather than inside the docker-compose.yml file, and that you should open it and insert your `APP_URL` and `APP_KEY` and update the rest as required:
APP_URL=http://in.localhost:8003/
APP_KEY=<insert your generated key in here>
APP_DEBUG=true
REQUIRE_HTTPS=false
IN_USER_EMAIL=
IN_PASSWORD=Moving variables out of the compose file into a `.env` file is a small change with a real benefit: the compose file stays a template that everyone shares, while the secrets live in one file that does not need to be committed. The downside is that the file is now a place where the deployment can be misconfigured, and the default values in it are development values, with `APP_DEBUG=true` and `REQUIRE_HTTPS=false` as shipped.
The two account variables, `IN_USER_EMAIL` and `IN_PASSWORD`, are worth pausing on. The README explains that if they are not set, the default user email and password is `[email protected]` and `changeme!` respectively. The intended flow is to set them before the first start, let the container create the primary account, and then delete the two variables once startup has completed. That is a workable pattern, but it depends on the operator reading the README before the first `docker compose up`, since an instance left with the default credentials is exposed.
Generating the APP_KEY before the first start
The application key has to exist before the container runs, and the README gives two commands depending on whether you have started the containers yet.
If you have not started them yet:
# If you haven't started the containers yet:
docker run --rm -it invoiceninja/invoiceninja-debian php artisan key:generate --showIf the containers are already running:
# Or if your containers are already running:
docker compose exec app php artisan key:generate --showEither way you copy the entire string and insert it in the .env file at `APP_KEY=base64....`.
The `--show` flag is what makes this usable outside a normal artisan workflow: it prints the key rather than writing it into a .env file inside the image, which matters because the container's filesystem is not where your configuration lives. The `docker run --rm -it` form pulls the image and executes the command in a throwaway container, so you can generate a key before any configuration exists. The `docker compose exec app` form requires that the app service is already up, which is the situation where the .env file is already mounted and the key can be pasted straight back in.
One extra constraint applies to local work. The README notes that for PDF generation using localhost, the domain name must end in .test for PDFs to generate correctly, because of Chrome's DNS resolver. That is not a stylistic preference; it is a documented requirement of the bundled Chrome when it resolves the address of the site it is rendering.
Starting, updating and the database host
Once the .env file is in place, the container starts with a single command:
docker compose up -dThe `-d` flag detaches, so the stack comes up in the background. The README carries one configuration note that matters on the first run: when performing the setup, the database host is `mysql`.
That is a detail about compose networking rather than about Invoice Ninja. The app service and the database service share a compose network, so the app reaches the database by the service name over the internal network, and the host name in the app's configuration has to be that name rather than localhost. Getting it wrong usually shows up as a connection error on first boot rather than a subtle misbehaviour later.
Upgrading is two commands, and the README recommends taking a backup first:
docker compose pull
docker compose up -d`docker compose pull` fetches the newer images, and `up -d` recreates the containers from them. The backup advice is not decoration. Pulling a new application image and recreating the container is a schema migration in waiting, since application releases carry database migrations, and the data lives in the database service rather than in the container. A database that is not backed up before the upgrade is a database you may not get back.
The image tags follow the upstream application version, and the release list in this repository shows both the debian-flavored tags and a separate invoiceninja-0.1.3 tag, so the publishing workflow maintains more than one tag stream.
The todo list is the honest part of the README
The README closes with a section that says the image is new, that it should provide much better support for all users, and that some items are left to complete. Three checkboxes remain unchecked: a backup script, integration of a soketi server, and adding Elasticsearch for site wide search.
Those three items describe the gap between this image and a self contained invoicing platform. The backup script matters most, because the upgrade instructions tell you to back up before pulling a new image, and a script that automates that would remove the most error prone step. Without it, backup is a manual procedure performed by the operator, and the correctness of a restore is unproven.
The soketi server integration matters for realtime features. The README does not yet bundle a soketi server, so until that integration lands, whatever depends on it falls outside what this compose setup provides out of the box.
Site wide search via Elasticsearch is a third absent piece, and the absence has a second order effect: without the search backend, a growing invoice history becomes harder to navigate than it should be, and a self hosted operator has to supply that themselves.
None of this makes the image unusable for evaluation or for a small deployment. It does mean the README is describing a work in progress image, and a reader who takes it at face value as a finished platform will be disappointed. The checkboxes are also useful in a different way, because they tell you exactly what a maintainer considers unfinished.
Licence, publishing pipeline and where support lives
The repository is licensed under GPL-2.0, with the LICENSE file at the top level. GPL-2.0 is a copyleft licence, so if you distribute a modified version of these Docker files you owe recipients the corresponding source, while running the unmodified image internally is unencumbered. The licence covers the packaging, not the Invoice Ninja application itself, which is a separate product with its own terms.
The publishing setup is visible in the badges. There is a build workflow badge for the Debian image and a publish workflow badge, both pointing at GitHub Actions definitions under .github/. The build and publish are separate workflows, which is the sensible arrangement: a pull request can build the image to prove it compiles, while only the main branch is allowed to push tags to the registry.
The repository structure is minimal by design. Alongside the README, the LICENSE and the CODE_OF_CONDUCT.md, there is the debian/ directory holding the image build for the Debian variant and the charts/ directory for the Kubernetes chart. Everything else, the application itself, lives in a different repository, so this one is purely the packaging layer.
Support is handled the way most commercial open source projects handle it. The README asks you to create an issue for bugs and points general queries at the project forum. The forum is the right channel for configuration and usage questions, since the repository issues are about the image rather than about the application.
Editorial conclusion
Adopt the invoiceninja-debian image when you want Invoice Ninja running under NGINX with PDF generation working out of the box, and when you are comfortable with the compose file's own opinion about the database and app wiring. Do not adopt it as a finished production artefact yet, because the README's own todo list still shows the backup script, the soketi server and site wide search as unchecked, and the default admin account exists until you set IN_USER_EMAIL and IN_PASSWORD. Before you start, generate a real APP_KEY with php artisan key:generate --show, set the primary account credentials in the .env file, and remember that the README requires a .test domain for local PDF generation to work with Chrome's DNS resolver.
Frequently asked questions
How do I start Invoice Ninja with the invoiceninja-debian image?
Clone the repository with the debian branch, put your values in the .env file, and run `docker compose up -d`. The README notes that during setup the database host is `mysql`.
How do I generate an APP_KEY for the invoiceninja-debian container?
Run `docker run --rm -it invoiceninja/invoiceninja-debian php artisan key:generate --show` before the containers are up, or `docker compose exec app php artisan key:generate --show` once they are running, then paste the whole string into the .env file at `APP_KEY=base64....`.
What are the default login credentials for the invoiceninja-debian image?
If `IN_USER_EMAIL` and `IN_PASSWORD` are not set in the .env file, the default account is `[email protected]` with the password `changeme!`. The README recommends setting them before the first start and removing them after startup.
Why do PDFs fail to generate on localhost in invoiceninja-debian?
The README states that for PDF generation using localhost, the domain name must end in .test, because of how Chrome's DNS resolver behaves in the bundled browser.
How do I update the invoiceninja-debian image?
Run `docker compose pull` followed by `docker compose up -d`. The README recommends taking a backup before updating, and the repository's todo list still has a backup script marked as unfinished.
What does the invoiceninja-debian image include?
NGINX webserver support, a built-in Chrome for PDF generation and other features, the Saxon XSLT 2 engine, OPcache and multi language support. A Docker image size badge is included in the README because the bundled browser makes the image large.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/invoiceninja-dockerfiles)Was this useful?