Skip to content

Deploying an InvoiceNinja App

Introduction

InvoiceNinja is an open-source invoicing and billing platform built on Laravel. Deploying InvoiceNinja with a Dockerfile on Klutch.sh delivers reproducible builds, managed secrets, and persistent storage for uploads and cache—all managed from klutch.sh/app. This guide covers installation, repository prep, a production-ready Dockerfile, deployment steps, Nixpacks overrides, and best practices for reliable billing workflows.


Prerequisites

  • A Klutch.sh account (create one)
  • A GitHub repository with your InvoiceNinja code (GitHub is the only supported git source)
  • Docker familiarity and PHP 8.1+ knowledge
  • Database credentials (MySQL/MariaDB) and Redis for queues/cache
  • Storage capacity for PDFs, logos, and uploads

For platform onboarding, see the Quick Start.


Architecture and ports

  • InvoiceNinja serves HTTP; set the internal container port to 9000 when using PHP-FPM with a bundled web server, or 8000/8080 if you serve directly. This guide uses 9000 for consistency with FPM + Nginx.
  • MySQL/MariaDB and Redis should run as separate Klutch.sh TCP apps. Expose them on port 8000 and connect internally on 3306 (MySQL/MariaDB) and 6379 (Redis).
  • Persistent storage is required for /var/www/html/storage and recommended for logs.

Repository layout

invoiceninja/
├── public/ # Web root
├── storage/ # Must be on persistent volume
├── docker/ # Optional helper scripts/configs
├── Dockerfile # Must be at repo root for auto-detection
├── composer.json
├── composer.lock
└── .env.example # Template only; no secrets

Keep secrets out of Git; store them in Klutch.sh environment variables.


Installation (local) and starter commands

Install dependencies and run locally before pushing to GitHub:

Terminal window
composer install --no-dev --optimize-autoloader
php artisan key:generate
php artisan migrate --force
php artisan serve --host=0.0.0.0 --port=9000

Optional helper start.sh for portability and Nixpacks fallback:

#!/usr/bin/env bash
set -euo pipefail
php artisan migrate --force
exec php artisan serve --host=0.0.0.0 --port=9000

Make it executable with chmod +x start.sh.


Dockerfile for InvoiceNinja (production-ready)

Place this Dockerfile at the repo root; Klutch.sh auto-detects it (no Docker selection in the UI):

FROM php:8.1-fpm
RUN apt-get update && apt-get install -y \
libpng-dev libjpeg-dev libfreetype6-dev libzip-dev libonig-dev libicu-dev libxml2-dev unzip git \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install pdo_mysql gd intl zip opcache \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /var/www/html
COPY . /var/www/html
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer && \
composer install --no-dev --optimize-autoloader && \
chown -R www-data:www-data /var/www/html/storage /var/www/html/bootstrap/cache
ENV PORT=9000
EXPOSE 9000
CMD ["php-fpm"]

Notes:

  • If you prefer Nginx + PHP-FPM in one container, add Nginx and a site config, still exposing 9000 internally for the app service.
  • Keep storage/ writable and on a persistent volume.

Environment variables (Klutch.sh)

Set these in the Klutch.sh app settings (Secrets tab) before deploying:

  • APP_ENV=production
  • APP_KEY=<generated-app-key>
  • APP_URL=https://example-app.klutch.sh
  • APP_DEBUG=false
  • DB_HOST
  • DB_PORT=3306
  • DB_DATABASE
  • DB_USERNAME
  • DB_PASSWORD
  • REDIS_HOST
  • REDIS_PORT=6379
  • QUEUE_CONNECTION=redis
  • SESSION_DRIVER=redis
  • CACHE_DRIVER=redis
  • LOG_CHANNEL=stderr
  • PORT=9000

If you deploy without the Dockerfile and need Nixpacks overrides:

  • NIXPACKS_BUILD_CMD=composer install --no-dev --optimize-autoloader
  • NIXPACKS_START_CMD=php -S 0.0.0.0:9000 -t public
  • NIXPACKS_INSTALL_PKGS="php81 php81Extensions.pdo_mysql php81Extensions.intl php81Extensions.gd php81Extensions.zip"

These keep InvoiceNinja compatible with Nixpacks defaults when a Dockerfile is absent.


Attach persistent volumes

In Klutch.sh storage settings, add mount paths and sizes (no names required):

  • /var/www/html/storage — required for uploads, cache, and logs.
  • /var/www/html/bootstrap/cache — optional if you want to persist caches.

Ensure these paths are writable inside the container.


Deploy InvoiceNinja on Klutch.sh (Dockerfile workflow)

  1. Push your repository (with the Dockerfile at the root) to GitHub.
  2. Open klutch.sh/app, create a project, and add an app.
  1. Connect the GitHub repository; Klutch.sh automatically detects the Dockerfile.
  2. Choose **HTTP** traffic for InvoiceNinja.
  3. Set the internal port to `9000`.
  4. Add the environment variables above (database, Redis, app key, and any `NIXPACKS_*` overrides if you temporarily deploy without the Dockerfile).
  5. Attach persistent volumes for `/var/www/html/storage` (and `/var/www/html/bootstrap/cache` if used), selecting sizes that fit your attachment and log needs.
  6. Deploy. Your app will be reachable at `https://example-app.klutch.sh`; attach a custom domain if desired.

For MySQL/MariaDB or Redis on Klutch.sh, create separate TCP apps, expose them on port 8000, and point DB_HOST or REDIS_HOST to those endpoints (internal ports 3306/6379).


Health checks and production tips

  • Add a /health endpoint or reuse a lightweight route for uptime monitoring.
  • Enforce HTTPS at the edge; forward HTTP to port 9000 internally.
  • Monitor storage usage for /var/www/html/storage and resize before it fills.
  • Rotate APP_KEY only during maintenance; changing it will invalidate sessions.
  • Back up your database and storage regularly; do not rely on container filesystems for durability.

InvoiceNinja on Klutch.sh combines reproducible Docker builds with managed secrets, persistent storage for billing assets, and flexible HTTP/TCP routing. With the Dockerfile at the repo root and ports set to 9000 for the app (8000 externally for TCP databases or caches), you can deliver a reliable invoicing platform without extra YAML or workflow overhead.