- Jinja 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .gitea/workflows | ||
| defaults | ||
| files/nginx | ||
| meta | ||
| tasks | ||
| templates | ||
| .gitignore | ||
| CHANGELOG.md | ||
| LICENSE | ||
| README.md | ||
InvoiceNinja
Deploys InvoiceNinja — an invoicing app — as a Docker Compose stack (nginx, MySQL, Redis, and the InvoiceNinja app itself), optionally fronted by Traefik.
Requirements
- Docker Engine with the Compose v2 plugin (
docker compose) community.dockerAnsible collection (>= 5.2.0)
Variables
| Variable | Default | Description |
|---|---|---|
ninja_instance |
invoiceninja |
Unique instance name. Used as Compose project name and container name prefix. Change when running multiple instances on the same host. |
ninja_docker_path |
/docker/ninja |
Host path for the Compose file (mounted read-only into containers). |
ninja_data_path |
/data/ninja |
Host path for persistent data (MySQL, Redis, app public/storage). |
ninja_version |
latest |
InvoiceNinja image tag (invoiceninja/invoiceninja-debian) to deploy. Pin to a specific tag in production. |
ninja_db_version |
8 |
MySQL image tag. Pin to a specific version in production. |
ninja_redis_version |
alpine |
Redis image tag. Pin to a specific version in production. |
ninja_db_name |
ninja |
MySQL database name. |
ninja_db_user |
ninja |
MySQL user. |
ninja_db_pass |
~ |
Required. MySQL user password. |
ninja_db_root_pass |
~ |
Required. MySQL root password. The mysql image refuses to start without one. |
ninja_app_key |
~ |
Required. Laravel APP_KEY. See Secret Generation. |
ninja_env |
production |
Laravel environment (APP_ENV). |
ninja_debug |
false |
Enable Laravel debug mode (APP_DEBUG). Should be false in production. |
ninja_app_name |
InvoiceNinja |
Application name shown in the UI (APP_NAME). |
ninja_user_email |
~ |
Initial admin email, only passed through if set. Leave unset to use the image's own default (admin@example.com). |
ninja_user_password |
~ |
Initial admin password, only passed through if set. Leave unset to use the image's own default (changeme!). |
ninja_port |
~ |
Host port bound to the web UI (container port 80). Either this or ninja_traefik must be set. |
ninja_url |
~ |
Required. Public hostname (no protocol prefix), used for APP_URL and the Traefik Host() rule. |
ninja_https |
true |
Whether APP_URL uses https:// and REQUIRE_HTTPS is enabled. Set to false if ninja_port is exposed with no TLS-terminating proxy in front of it. |
ninja_trusted_proxies |
* |
Comma-separated list of trusted proxy IPs/CIDRs, or * to trust all. Must include your reverse proxy (e.g. Traefik) or InvoiceNinja won't see real client IPs/scheme. |
ninja_redis_pass |
~ |
Redis password. Leave unset to run Redis without authentication. |
ninja_mail_conf |
~ |
SMTP mail configuration dict. When set, enables outbound email. See Mail below. |
ninja_traefik |
false |
Enables Traefik integration for the web UI. Either this or ninja_port must be set. |
ninja_traefik_certresolver |
default |
Traefik certificate resolver name. |
ninja_traefik_web_entrypoint |
websecure |
Traefik entrypoint name for the web UI HTTPS router. |
ninja_uninstall |
false |
Stops and removes all containers and the compose directory. |
ninja_purge |
false |
Also removes ninja_data_path (MySQL, Redis, uploaded storage). Requires ninja_uninstall: true. Irreversible. |
Secret Generation
ninja_db_pass, ninja_db_root_pass, and ninja_app_key must be set before the first deploy:
openssl rand -hex 32 # → ninja_db_pass / ninja_db_root_pass
docker run --rm -it invoiceninja/invoiceninja-debian php artisan key:generate --show # → ninja_app_key
Copy the output values into your inventory:
ninja_db_pass: "..."
ninja_db_root_pass: "..."
ninja_app_key: "base64:..."
Note: The image only stores its generated
APP_KEYin/var/www/html/.env, which is not on a persisted volume — recreating theappcontainer (e.g. bumpingninja_version) withoutninja_app_keyset generates a brand-new key and permanently breaks decryption of anything encrypted with the old one. Set it explicitly to keep it stable across recreations.
Usage
Minimal setup, exposing the web UI directly on a host port (no TLS termination, so ninja_https must be false):
ninja_url: ninja.example.com
ninja_https: false
ninja_port: 8090
ninja_db_pass: "{{ vault_ninja_db_pass }}"
ninja_db_root_pass: "{{ vault_ninja_db_root_pass }}"
ninja_app_key: "{{ vault_ninja_app_key }}"
Or behind Traefik instead of a published port:
ninja_url: ninja.example.com
ninja_traefik: true
ninja_db_pass: "{{ vault_ninja_db_pass }}"
ninja_db_root_pass: "{{ vault_ninja_db_root_pass }}"
ninja_app_key: "{{ vault_ninja_app_key }}"
When ninja_mail_conf is set, InvoiceNinja's email functionality is enabled (invoice delivery, password resets). When unset, mail is only logged, not sent.
Required keys: host, username, password
Optional keys:
| Key | Default | Description |
|---|---|---|
port |
587 |
SMTP port. |
encryption |
tls |
SMTP encryption method (tls, ssl, or unset). |
address |
username |
From address for outbound mail. Set separately when the auth login differs from the desired sender address. |
name |
ninja_app_name |
From name for outbound mail. |
Example:
ninja_mail_conf:
host: smtp.example.com
username: ninja@example.com
password: "{{ vault_ninja_smtp_password }}"
address: invoices@example.com
Traefik
Setting ninja_traefik: true enables Traefik integration. The role attaches the nginx container to the external traefik_web network (must already exist — created by a Traefik instance elsewhere) and adds routing labels:
- Web UI — HTTPS router on
ninja_traefik_web_entrypoint(default:websecure) forninja_url
ninja_traefik: true
ninja_url: ninja.example.com
ninja_traefik_certresolver: default
ninja_traefik_web_entrypoint: websecure
Leave ninja_port unset when using Traefik so the port is not also bound directly on the host.
Uninstall
To stop and remove all containers and the compose directory:
ninja_uninstall: true
To also wipe all persistent data including the database and uploaded storage (irreversible):
ninja_uninstall: true
ninja_purge: true