Thanks for taking the time to setup Invoice Ninja. The applications requires PHP >= 5.5.9 and MySQL. If you run into any problems you can post to our forum or feel free to contact us.

All Pro and Enterprise features from our hosted app are included in both the zip file and the GitHub repository.

Detailed Guides

Automated Installers

Step 1: Download the code

You can either download the zip file below or checkout the code from our GitHub repository. The zip includes all third party libraries whereas using GitHub requires you to use Composer to install the dependencies.


Release Notes | Roadmap

Step 2: Upload the code to your server

Copy the ZIP file to your server and then check that the storage folder has 755 permissions and is owned by the webserver user.

cd /path/to/ninja/code
chmod -R 755 storage
sudo chown -R www-data:www-data storage bootstrap public/logo

Step 3: Setup the database

You’ll need to create a new database along with a user to access it. Most hosting companies provide an interface to handle this or you can run the SQL statements below.

CREATE USER 'ninja'@'localhost' IDENTIFIED BY 'ninja';
GRANT ALL PRIVILEGES ON * . * TO 'ninja'@'localhost';

Step 4: Configure the web server

Please see these guides for detailed information on configuring Apache or Nginx.

Once you can access the site the initial setup screen will enable you to configure the database and email settings as well as create the initial admin user.

The best practice to remove public/ from the URL is to map the webroot to the folder, alternatively you can uncomment RewriteRule ^(.*)$ public/$1 [L] in the .htaccess file.


Review the .env.example file to see additional settings.

Recurring invoices and reminder emails

Create a cron to call the ninja:send-invoices and ninja:send-reminders Artisan commands once daily.

0 8 * * * /usr/local/bin/php /path/to/ninja/artisan ninja:send-invoices
0 8 * * * /usr/local/bin/php /path/to/ninja/artisan ninja:send-reminders

Postmark bounce and open notifications

Include the following two setting in the .env file, the rest of the email settings can be commented out.


In your Postmark account settings make sure ‘Open tracking’ is enabled and enter the following values under Settings > Outbound.

Bounce webhook:
Open webhook:

Social/One-Click Login

Create an application in either Google, Facebook, GitHub or LinkedIn and then set the client id, secret and redirect URL in the .env file. For example:



We use to attach PDFs to emails sent by background processes. Check for the following line in the .env file to enable this feature or sign up to increase your daily limit.

You can install PhantomJS to generate the file locally, to enable it add PHANTOMJS_BIN_PATH=/usr/local/bin/phantomjs. To determine the path run which phantomjs from the command line.

Custom Fonts

Follow these steps to add custom ttf fonts: ie, Google fonts

  • Create a new folder in public/fonts/invoice-fonts/ and copy over the ttf files
  • Run grunt dump_dir
  • Add the font to database/seeds/FontsSeeder.php
  • Run php artisan db:seed --class=FontsSeeder
  • Clear the cache by adding ?clear_cache=true to the end of the URL

Google Map

You need to create a Google Maps API key for the Javascript, Geocoding and Embed APIs and then add GOOGLE_MAPS_API_KEY=your_key to the .env file.

Using a Proxy

If you need to set a list of trusted proxies you can add a TRUSTED_PROXIES value in the .env file. ie,


  • Check your webserver log (ie, /var/log/apache2/error.log) and the application logs (storage/logs/laravel-error.log) for more details or set APP_DEBUG to true in .env
  • To resolve [Symfony\Component\Debug\Exception\FatalErrorException] Class 'SomeClass' not found try running php artisan optimize
  • To resolve file_put_contents(...): failed to open stream: Permission denied run chmod -R 777 storage then chmod -R 755 storage
  • If index.php is in the URL it likely means that mod_rewrite needs to be enabled.
  • Running composer dump-autoload and composer update can sometimes help with composer problems.
  • If you’re using a subdomain. ie, You will need to add RewriteBase / to public/.htaccess otherwise it may fail with “Request exceeded the limit of 10 internal redirects due to probable configuration error.” messages in the logs.
  • Composer error: Fatal error: Allowed memory size of... Try the following: php -d memory_limit=-1 /usr/local/bin/composer install
  • PHP Fatal error: Call to undefined method Illuminate\Support\Facades\Session::get() try deleting bootstrap/cache/services.php


  • Our developer guide has more details about our application’s codebase.
  • You can add currencies and date/time formats by adding records to their respective tables in the database. This data is cached, to clear it load any page with ?clear_cache=true added to the end of the URL.
  • The JavaScript and CSS files are compiled to built files, you can recompile them by running bower install and then gulp.


Note: we recommend backing up your database before updating the app.

To update the app you just need to copy over the latest code. The app tracks the current version in a file called version.txt, if it notices a change it loads /update to run the database migrations.

If the auto-update fails you can manually run the update with the following commands. Once completed add ?clear_cache=true to the end of the URL to clear the application cache.

composer dump-autoload --optimize
php artisan optimize --force
php artisan migrate
php artisan db:seed --class=UpdateSeeder

We’ve seen some updates fail when moving the app to a new server because the MySQL default storage engine has changed with MySQL 5.7. If you see a SQLSTATE[HY000]: General error: 1215 error you may be able to fix it by running this SQL query.

Version 2.6 notes

  • Make sure the .env file includes APP_CIPHER=rijndael-128

Version 2.5.1 notes

  • Minimum PHP version is now 5.5.9

Version 2.0 notes

  • Copy .env.example to .env and set config settings
  • Set the app cipher to rijndael-256 to support existing passwords
  • Check that /path/to/ninja/storage has 755 permissions and is owned by the webserver user