The Problem with SaaS Invoicing for Canadian Freelancers
As a Canadian freelancer, you need professional invoicing software that respects your privacy, keeps financial data within Canadian borders, and doesn’t eat into your profits with monthly SaaS fees. Invoice Ninja is a powerful source-available invoicing platform (free to self-host) that gives you complete control over your billing workflow while maintaining PIPEDA compliance through Canadian hosting.
Many freelancers start with spreadsheets or basic templates, but as your client list grows, you need automated reminders, recurring invoices, client portals, and payment tracking. Commercial solutions like FreshBooks or QuickBooks Online charge significant monthly fees per user and store your financial data on US servers. Invoice Ninja gives you all the professional features for free, running on your own Canadian-hosted server where you control the data.
Canadian businesses increasingly prioritize keeping financial data within Canadian borders, and self-hosting Invoice Ninja on a Canadian server addresses both privacy and cost concerns.
What You’ll Need
For this setup, we recommend a Cloud VPS with:
- CPU: 2+ cores (handles concurrent users and background tasks)
- RAM: 4GB minimum (8GB recommended for production with 50+ active clients)
- Storage: 40GB SSD (20GB for system, 20GB for invoice PDFs and attachments)
- OS: Ubuntu 24.04 LTS (stable, well-documented, long-term support)
- Bandwidth: 2TB/month minimum (invoice PDFs and client portal traffic)
Canadian Web Hosting offers Cloud VPS starting at competitive rates with Canadian data centres and 24/7 support. Not comfortable managing this yourself? CWH offers Managed Support — our team will handle setup, security patches, and ongoing maintenance so you can focus on client work instead of server administration.
Domain requirement: You’ll need a domain name for professional invoicing (e.g., invoices.yourbusiness.ca). CWH provides free domain registration with annual hosting plans, or you can transfer an existing domain to our Canadian DNS servers for faster resolution and better privacy protection.
Installation Steps
Step 1: Server Preparation
Update your system and install prerequisites:
sudo apt update && sudo apt upgrade -ysudo apt install -y curl git unzip
Verification: Check Ubuntu version with lsb_release -a — should show 24.04. If you’re on an older version, consider upgrading or starting with a fresh 24.04 install for optimal compatibility.
Step 2: Install Docker and Docker Compose
Invoice Ninja runs best in Docker containers, which provide isolation, easy updates, and consistent environments:
# Install Docker
curl -fsSL https://get.docker.com -o get-docker.shsudo sh get-docker.shsudo usermod -aG docker $USER# Install Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-composesudo chmod +x /usr/local/bin/docker-compose
Log out and back in for group changes to take effect. Verify installation:
docker --versiondocker-compose --version
You should see Docker version 25+ and Docker Compose version 2.20+. If you encounter permission errors, ensure your user is in the docker group: groups $USER | grep docker.
Step 3: Create Invoice Ninja Directory Structure
mkdir -p ~/invoice-ninja
cd ~/invoice-ninja
This creates a dedicated directory for your Invoice Ninja instance. Using a separate directory keeps configuration files organized and makes backups straightforward. Consider using a descriptive name if you’ll run multiple applications: mkdir -p ~/apps/invoice-ninja-production.
Step 4: Create Docker Compose Configuration
Create docker-compose.yml:
version: '3.8'services: app: image: invoiceninja/invoiceninja:latest container_name: invoiceninja_app restart: unless-stopped ports: - "8080:80" environment: - APP_KEY=base64:YOUR_APP_KEY_HERE - APP_URL=http://your-domain.com - DB_HOST=db - DB_DATABASE=ninja - DB_USERNAME=ninja - DB_PASSWORD=secure_password_here - MAIL_DRIVER=smtp - MAIL_HOST=smtp.your-email-provider.com - MAIL_PORT=587 - MAIL_USERNAME=your-email@example.com - MAIL_PASSWORD=your-email-password - MAIL_ENCRYPTION=tls volumes: - ./storage:/var/www/app/storage - ./public:/var/www/app/public depends_on: - db db: image: mysql:8.0 container_name: invoiceninja_db restart: unless-stopped environment: - MYSQL_DATABASE=ninja - MYSQL_USER=ninja - MYSQL_PASSWORD=secure_password_here - MYSQL_ROOT_PASSWORD=secure_root_password_here volumes: - ./mysql:/var/lib/mysql
Security note: Generate strong passwords using openssl rand -base64 32 for DB_PASSWORD and MYSQL_ROOT_PASSWORD. Never use default or weak passwords for financial applications.
Step 5: Generate App Key and Configure
# Generate a secure app keydocker run --rm invoiceninja/invoiceninja php artisan key:generate --show# Copy the output and replace YOUR_APP_KEY_HERE in docker-compose.yml# Also update APP_URL with your actual domain
The app key is used for encryption within Invoice Ninja. If you lose it, encrypted data becomes unrecoverable. Store a backup of this key in a password manager or secure location. Example output: base64:2e9a1c3f5g7h9j1k3m5n7p9r1s3t5v7x9z1b3d5f7h9j1l=
Step 6: Start Invoice Ninja
docker-compose up -d
The -d flag runs containers in detached mode. Check they’re running:
docker-compose ps
Both “app” and “db” services should show “Up” status. If either shows “Exit” or restarting, check logs: docker-compose logs app.
Step 7: Run Initial Setup
docker-compose exec app php artisan migrate --seed
docker-compose exec app php artisan db:seed
These commands create the database schema and populate it with initial data (tax rates, payment terms, invoice templates). The process takes 30-60 seconds. Watch for any error messages — common issues include MySQL not being ready (wait 30 seconds and retry) or permission problems with storage directories.
Configuration
Email Setup for Canadian Businesses
For reliable email delivery from your Canadian-hosted Invoice Ninja:
# Using CWH Hosted Email (recommended for Canadian data residency)MAIL_DRIVER=smtp
MAIL_HOST=mail.canadianwebhosting.com
MAIL_PORT=587
MAIL_USERNAME=your-email@yourdomain.ca
MAIL_PASSWORD=your-email-password
MAIL_ENCRYPTION=tls
Why CWH Hosted Email? Canadian data centres mean your email metadata stays in Canada, important for PIPEDA compliance. Our email servers have established reputations with major providers (Gmail, Outlook, Yahoo), reducing the chance of invoices being marked as spam. For high-volume senders (500+ invoices/month), consider our Business Email plans with dedicated IP addresses and enhanced delivery monitoring.
Custom Domain Configuration
To use your own domain with Invoice Ninja:
- Point DNS: Add an A record pointing to your CWH VPS IP
- Configure Nginx Reverse Proxy: Create
/etc/nginx/sites-available/invoiceninja:
server { listen 80; server_name invoices.yourdomain.ca; location / { proxy_pass http://localhost:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; }}
- Enable HTTPS with Let’s Encrypt:
sudo apt install -y certbot python3-certbot-nginxsudo certbot --nginx -d invoices.yourdomain.ca
Important: Update APP_URL in docker-compose.yml to https://invoices.yourdomain.ca after enabling HTTPS. Mixed content (HTTP/HTTPS) breaks the client portal and payment integrations.
Canadian Tax Configuration
Invoice Ninja supports Canadian tax rules out of the box. Configure under Settings ? Tax Rates:
- GST/HST: 5% (Alberta, Northwest Territories, Nunavut, Yukon)
- HST: 13% (Ontario), 15% (New Brunswick, Newfoundland and Labrador, Prince Edward Island), 14% (Nova Scotia — reduced from 15% in April 2025)
- QST + GST: 14.975% (Quebec — 9.975% QST + 5% GST)
Enable “Apply tax to line items” for proper Canadian invoicing. For clients in different provinces, create client-specific tax rates or use the “Tax by Province” feature in Invoice Ninja v5.3+.
Verify It Works
- Access the dashboard: Navigate to
https://invoices.yourdomain.ca - Default login:
admin@example.com/password - Change credentials immediately in Settings ? User Management
- Test invoice creation: Create a sample invoice and send it to yourself
- Check payment integration: Test Stripe or PayPal sandbox if configured
Comprehensive verification checklist:
- ? Invoice PDF generates correctly (check formatting, logo, tax calculations)
- ? Email delivery works (invoice reaches inbox, not spam)
- ? Client portal accessible (clients can view invoices and make payments)
- ? Recurring invoices schedule properly (test with 5-minute recurrence)
- ? Backup script runs successfully (manual test:
./backup-invoiceninja.sh)
Production Hardening
Firewall Rules
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw --force enable
For additional security, consider:
# Rate limiting to prevent brute force attackssudo ufw limit 22/tcp
# Restrict SSH to your IP (if static)sudo ufw allow from YOUR_IP to any port 22
Backup Strategy
Create automated backups for your Invoice Ninja data:
# Create backup scriptcat > ~/backup-invoiceninja.sh << 'EOF'#!/bin/bashBACKUP_DIR="/home/ubuntu/backups"DATE=$(date +%Y%m%d_%H%M%S)# Backup databasedocker-compose exec db mysqldump -u ninja -psecure_password_here ninja > $BACKUP_DIR/ninja_db_$DATE.sql# Backup storage filestar -czf $BACKUP_DIR/ninja_storage_$DATE.tar.gz ~/invoice-ninja/storage# Keep only last 7 days of backupsfind $BACKUP_DIR -name "*.sql" -mtime +7 -deletefind $BACKUP_DIR -name "*.tar.gz" -mtime +7 -deleteEOFchmod +x ~/backup-invoiceninja.sh# Add to cron(crontab -l 2>/dev/null; echo "0 2 * * * /home/ubuntu/backup-invoiceninja.sh") | crontab -
Off-site backup: For critical financial data, enable CWH’s automated backup service. Backups are encrypted, stored in separate Canadian data centres, and retained for 30 days with one-click restoration.
Log Rotation
Configure Docker log rotation to prevent disk filling:
{ "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" }}
Apply by creating /etc/docker/daemon.json and restarting Docker: sudo systemctl restart docker. Monitor logs with: docker-compose logs --tail=50 --follow app.
Security Updates
Subscribe to Invoice Ninja security announcements on GitHub. When updates are released:
cd ~/invoice-ninjadocker-compose pull
docker-compose down
docker-compose up -d
docker system prune -f
Test thoroughly after updates — check invoice generation, email delivery, and payment processing.
Troubleshooting
Issue 1: Container Won’t Start
Symptom: docker-compose up fails with database connection errors
Cause: MySQL container needs time to initialize
Fix:
# Wait 30 seconds, then restartsleep 30
docker-compose restart app
If persistent: Check MySQL logs: docker-compose logs db. Common issues include insufficient memory (increase swap) or corrupted volume (delete ./mysql and restart).
Issue 2: Email Not Sending
Symptom: Invoices sent but no email received
Cause: SMTP configuration incorrect or port blocked
Fix:
- Check CWH Hosted Email credentials
- Test SMTP connection:
docker-compose exec app php artisan tinker>>> Mail::raw('Test email', function($message) {>>> $message->to('test@example.com')->subject('Test');>>> });
Advanced debugging: Check Invoice Ninja email logs at storage/logs/laravel.log or enable debug mode temporarily: APP_DEBUG=true in docker-compose.yml.
Issue 3: Slow Performance
Symptom: Invoice Ninja dashboard loads slowly
Cause: Insufficient RAM or need for caching
Fix:
- Upgrade to 8GB RAM VPS
- Enable Redis caching in
.env:
CACHE_DRIVER=redis
REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379
Add Redis service to docker-compose.yml and rebuild: docker-compose up -d --build.
Issue 4: PDF Generation Fails
Symptom: “Download PDF”
Issue 4: PDF Generation Fails
Symptom: “Download PDF” button generates blank or corrupted PDF
Cause: Missing PHP extensions or insufficient memory for PDF rendering
Fix:
# Rebuild with additional PHP extensionsdocker-compose down
docker-compose build --no-cache
docker-compose up -d
If issue persists, check container logs for wkhtmltopdf errors and consider increasing PHP memory limit in .env: PHP_MEMORY_LIMIT=256M.
Issue 5: Canadian Tax Calculations Incorrect
Symptom: GST/HST calculations don’t match CRA requirements
Cause: Tax rate configuration or rounding differences
Fix:
- Verify tax rates under Settings ? Tax Rates match current CRA percentages
- Enable “Calculate tax on tax” for HST provinces
- Check “Round tax amounts” setting matches your accounting software
- Test with CRA’s online GST/HST calculator for validation
Conclusion
Invoice Ninja gives Canadian freelancers a professional, self-hosted invoicing solution that keeps financial data within Canadian borders. With CWH Cloud VPS, you get the performance and reliability needed for your billing system, plus the option of Managed Support if you’d rather focus on client work than server maintenance.
By self-hosting, you save significantly compared to commercial alternatives while maintaining full control over your financial data. Canadian hosting supports PIPEDA compliance and faster access for your Canadian clients.
Next steps for your invoicing system:
- Set up automated payment reminders: Reduce late payments by 40% with scheduled reminders at 7, 14, and 30 days past due
- Configure client portal: Let clients view invoices, make payments, and download receipts 24/7
- Integrate with Canadian payment processors: Connect Stripe (2.9% + $0.30) or PayPal (2.9% + $0.30) for instant online payments
- Implement recurring invoices: Automate monthly retainers or subscription billing
- Set up expense tracking: Capture business expenses directly in Invoice Ninja for simplified tax preparation
- Enable time tracking: Bill accurately for hourly work with built-in timer and project tracking
When to consider professional help: If you’re billing $50,000+ annually or have complex tax situations (multiple provinces, international clients, GST/HST registrations), our Managed Support team can ensure your invoicing system is optimized, secure, and compliant. We handle updates, backups, security patches, and performance tuning so you can focus on growing your business.
Related posts:
- 8 Self-Hosted Productivity Apps for Small Teams — includes Invoice Ninja in our roundup
- Canadian Data Residency: What It Means for Your Business — understand why hosting in Canada matters for financial data
- Let’s Encrypt Setup Guide: Free HTTPS for Your Domain — secure your invoice portal with free SSL certificates
- CWH Cloud VPS — the perfect platform for self-hosted apps like Invoice Ninja
- CWH Managed Support — let our team handle server management while you focus on client work
Final thought: Your invoicing system is the financial heartbeat of your freelance business. By choosing self-hosted software on Canadian infrastructure, you invest in privacy, control, and long-term cost savings while supporting local hosting providers. Start with our Cloud VPS plan, and upgrade as your business grows.
Be First to Comment