Intro

If you’re searching for a great gift for your significant other, whether it’s for Valentine’s Day or their birthday, I have an idea for you!

Speaking on behalf of my own significant other, I can tell you with 100% certainty that she loves owing me money (and I’m sure your significant other will too). I love it too, and you know what else she really loves? When I remind her that she owes me money with an invoice that I’ve emailed her. If this sounds like a gift you’d like to give to your partner or family members, then follow along!

Oh, and if you need it for an actual business purpose, then I suppose you could follow along as well.

Setting Up Invoice Ninja

Invoice Ninja is probably the best open-source invoice software that I know of for managing invoices. It has been crafted by some very passionate people who put a lot of thought into this product. If you’re looking for a non-self-hosted solution, I would definitely recommend paying them a visit at: https://invoiceninja.com/

Now that we’ve covered that, let’s jump right into how to do this:

Step 1 Clone The Repo

Clone the docker repo which is super easy if you know git

git clone https://github.com/invoiceninja/dockerfiles

As always confirm the source!

Step 2 Update The Docker Compose File

There are some configurations in the docker compose file that I don’t agree with or causes various problems.

Step 2b) Update Nginx conf configuration

Replace

   - ./config/nginx/in-vhost.conf:/etc/nginx/conf.d/in-vhost.conf:ro

with

 - ./config/nginx/in-vhost.conf:/etc/nginx/conf.d/default.conf:ro

We do this because in the Nginx container, we pull down the default nginx.conf file, which contains a line stating this:

include /etc/nginx/conf.d/*.conf;

This would import not only our in-vhost.conf, but also the default.conf, which is present in the conf.d folder. Since Nginx executes in alphabetical order, we would end up with a 502 error when trying to access the website. So, by replacing the file, we no longer encounter this problem.

Step 3 Update Nginx port (optional)

“If you’re planning to have different applications running on your server, it’s a no-brainer: don’t serve them on port 80. I will have a follow-up tutorial on how you can manage all of this!

We can the port by making the following changes:

  ports:
     - "80:80"
     #- "443:443"

to

  ports:
      - "9081:80"
      #- "443:443"

This simply changes the port. So, assuming your server IP is 192.168.0.14, the website will be resolved when you enter http://192.168.0.14 in your browser. Previously, you would have to enter http://192.168.0.14:9081, but we can make this prettier in the future.

Step 4 Update permissions

Just run the following commands!

sudo chown -R $(whoami):1500 docker
sudo chmod -R 775 docker 

When the Invoice Ninja Docker container is running, it operates under the user/group permission named 1500. Therefore, we’re going to grant full permissions to ourselves and to the group 1500, while giving everyone else read-only access. If you wish to make this more restrictive, feel free to do so, but the crucial point is that the user 1500 has full permissions.

For additional information, these folders under the Docker folder are where the database will store its data and where Invoice Ninja will save static content such as pictures. Therefore, ensure that there is enough space!

Step 5 Generate the APP_KEY

Run the following command:

docker run --rm -it invoiceninja/invoiceninja php artisan key:generate --show

This should output something like

base64:Ym1f/J2oajokGjTZbBcsxBQQ0UVdJkasdfase2=

Keep this value handy

Step 6 Prepare the env file (Optional)

Keep in mind that adding credentials in this way is how you would configure the application if you don’t mind having your credentials in a plain text file temporarily. If you prefer a more ‘secure’ approach, then look out for my next article (whenever I publish it), where I’ll cover the same setup not only with Docker secrets but also with HashiCorp Vault. However, in all seriousness, it’s not too bad; you can simply delete the sensitive credentials from the env file once the app is running.

APP_URL=http://in.localhost:8003
APP_KEY=<APP_KEY We generated in the last step> 
APP_DEBUG=true
REQUIRE_HTTPS=false
PHANTOMJS_PDF_GENERATION=false 
PDF_GENERATOR=snappdf
TRUSTED_PROXIES='*'


QUEUE_CONNECTION=database

# DB connection
DB_HOST=db
DB_PORT=3306
DB_DATABASE=ninja
DB_USERNAME=ninja
DB_PASSWORD=ninja

# Create initial user
# Default to these values if empty
# IN_USER_EMAIL=admin@example.com
# IN_PASSWORD=changeme!
IN_USER_EMAIL=
IN_PASSWORD=

# Mail options
# This is an example of a smtp setup
MAIL_MAILER=smtp
MAIL_HOST=<my mail host>
MAIL_PORT=<mail port>
MAIL_USERNAME=<email address>
MAIL_PASSWORD='<passwordToTheEmailAddress>'
MAIL_ENCRYPTION=<encryption> 
MAIL_FROM_ADDRESS='<the email address you want to show up in the email>'
MAIL_FROM_NAME='<The name of the emailer>'

# MySQL
MYSQL_ROOT_PASSWORD=ninjaAdm1nPassword
MYSQL_USER=ninja
MYSQL_PASSWORD=ninja
MYSQL_DATABASE=ninja

Testing your email credentials

Unfortunately, at the time of writing, sending an email in the UI might appear to fail because of an issue with how PDFs are rendered in the browser. To check ahead of time, we can leverage the following commands to see if email is setup correctly:

  • You can test the email logic by running the following steps:
    • docker container ls # and get the container id of dockerfiles-app or whatever you named it.
    • docker exec -it <contianerId> sh
    • php artisan tinker
    • Mail::raw('Hello World!', function($msg) {$msg->to('my@myemail.com')->subject('Test Email'); })
    • If your credentials are setup correctly you should get a message like = Illuminate\Mail\SentMessage {#7050}
    • If not an error message should give more details.

Some extra notes/debugging

  • I would suggest wrapping passwords with single quotes.
  • If you started the application before adding the credentials, you may have to destroy the volumes/container. This is less painful than trying to update everything.
  • If you encounter an xmlhttprequest error, then you’re experiencing the PDF issue I mentioned before.

Closing

Is there something I missed or you feel should be added? Shot me an email at blog@ryanpiper.live!