Invio
Overview
Invio is a lightweight, self-hosted invoicing app. You create clients, build invoices and quotes, track which invoices are paid, and share a secure link so a client can view and download an invoice without creating an account. Your data stays on your own virtual machine in a local database.
This SecureAnyCloud image runs Invio the officially supported way: the single upstream container image, pinned by digest to release v2.1.1 and run under systemd. Security is enforced from first boot, before any port is reachable.
Invio is the work of its author, kittendevv. This image is produced by SecureAnyCloud and is not affiliated with, endorsed by, or sponsored by Invio. It ships the unmodified upstream release, which its author has placed in the public domain under The Unlicense. The verbatim licence text ships inside the image under /usr/share/doc/sac/third-party-licences.
What you get:
- Invio v2.1.1, the official upstream container pinned by digest to the release
- An embedded SQLite database on a local path, with no external database to run
- The app and its database bound to the loopback interface, with only an nginx front end exposed
- HTTPS terminated by nginx with a per-VM self-signed certificate
- A unique admin password and a unique JWT signing key generated for each VM on first boot, because Invio signs its login sessions with a secret key
- The admin account seeded into a brand new database, so the instance starts clean and empty with no default account and no shipped data
- 24/7 SecureAnyCloud support
Prerequisites
You need an Azure subscription, an SSH key pair, and a virtual network.
The web interface is served over HTTPS on port 443. In your network security group (NSG), allow inbound port 22 for SSH, ideally from your management address only, and port 443 for the web interface.
The recommended size is Standard_B2s (2 vCPU, 4 GiB). Invio is very light and runs comfortably on that size.
Deploy from the Azure Marketplace
- In the Azure portal, search the Marketplace for Invio on Ubuntu 24.04 LTS by SecureAnyCloud and select Create.
- Choose your subscription, resource group and region.
- Set the VM size to
Standard_B2s, choose SSH public key authentication, and set the admin username. - On the Networking tab, allow inbound 443 (HTTPS) and 22 (SSH). Restrict SSH to your own address where possible.
- Review and create the VM. When it is running, note its public IP address.
Deploy with the Azure CLI
You can deploy the same image from the command line. Adjust the resource group name and location to suit your environment.
az group create --name invio-rg --location eastus
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:invio:default:latest
az vm create \
--resource-group invio-rg \
--name invio \
--image sac1647283583153:invio:default:latest \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
# Allow the web interface (443) and SSH (22)
az vm open-port --resource-group invio-rg --name invio --port 443 --priority 1001When the VM is running, browse to https://<vm-ip>/ and continue below.
First boot: your unique admin password
On first boot, before the web port is reachable, the image generates a unique admin password and a unique JWT signing key for your VM. It also seeds the admin account into a fresh database and creates a self-signed TLS certificate. The upstream default password is never used.
Connect over SSH and read your VM's admin password:
sudo cat /root/invio-credentials.txtOnly root can read this file. It contains your Invio URL, the admin username (admin) and the per-VM admin password. Keep the password safe.
Sign in
Browse to https://<vm-ip>/. The certificate is a per-VM self-signed certificate, so your browser warns you once. Accept the warning to continue. For production, put your own domain and a trusted certificate in front of Invio (see below).
Sign in with the username admin and the password from the credentials file.
Create your first client and invoice
- Open Customers and add a client with their name and contact details.
- Open Invoices, select New, choose the client, add one or more line items (description, quantity and unit price), and save. Invio calculates the totals for you.
- When you are ready, select Publish. Then use Download PDF, or share the secure invoice link so your client can view and download the invoice without an account.
Verify the deployment
Run these commands on the VM over SSH. They confirm that the services are running and that the web interface answers over HTTPS:
# Docker, the Invio container and nginx should all be active systemctl is-active docker invio nginx
# The login page is served through nginx over HTTPS (self signed -> -k)
curl -sk -o /dev/null -w 'https login page -> HTTP %{http_code}\n' https://127.0.0.1/login
# HTTP is redirected to HTTPS
curl -s -o /dev/null -w 'http redirect -> HTTP %{http_code}\n' http://127.0.0.1/Secure by default
Invio signs every login session with the JWT_SECRET key, so a shipped default key would let anyone forge an admin session. This image generates a unique key and a unique admin password for each VM on first boot. Neither the upstream default password nor a shared signing key is ever present.
The commands below show that the upstream default password is rejected and that only your per-VM password authenticates:
# The upstream default password is rejected curl -sk -o /dev/null -w 'default password -> HTTP %{http_code}\n' \
-X POST https://127.0.0.1/api/v1/auth/login \
-H 'content-type: application/json' \
-d '{"username":"admin","password":"supersecret"}'
# Your per VM password authenticates (returns a session token)
curl -sk -o /dev/null -w 'your password -> HTTP %{http_code}\n' \
-X POST https://127.0.0.1/api/v1/auth/login \
-H 'content-type: application/json' \
-d '{"username":"admin","password":"<INVIO_ADMIN_PASSWORD>"}'The first request returns 401 (rejected). The second returns 200.
Data and backups
Invio stores everything in a single SQLite database on the VM at /var/lib/invio/data/invio.db, mounted into the container at /app/data. To back up your data, stop the app briefly and copy the database file:
sudo systemctl stop invio
sudo cp -a /var/lib/invio/data/invio.db /var/lib/invio/data/invio.db.backup
sudo systemctl start invioStore the backup somewhere safe, off the VM. To restore, stop the app, replace invio.db and start the app again.
Move to your own domain with TLS
For production, put your own domain name and a trusted certificate in front of Invio instead of the per-VM self-signed certificate. Point a DNS record at the VM, then terminate TLS for your domain. You can use your own certificate on the built-in nginx, or place Invio behind an Azure Application Gateway or another reverse proxy.
Restrict the NSG so that only the addresses that need access can reach the VM.
Licensing
Invio is released into the public domain under The Unlicense, so there is no per-seat fee for the software and no source or notice obligation. The verbatim licence text ships inside the image at /usr/share/doc/sac/third-party-licences/invio-2.1.1-LICENSE.txt.
The SecureAnyCloud charge covers packaging, security patching, image maintenance and 24/7 support. This image is produced by SecureAnyCloud and is not affiliated with, endorsed by, or sponsored by Invio or its author.
Support
For help with this image, email sales@secureanycloud.com. For questions about Invio itself, see the upstream project at https://github.com/kittendevv/Invio.
Deploy on Azure
Launch Invio on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com