Troubleshooting
Purpose Statement: This document covers the most frequent operational issues in the Invoice Ninja application stack and their solutions.
Table of Contents
Application Issues
Application Won't Start
Symptoms:
- Container exits immediately
- Health check fails
- Application logs show startup errors
Diagnostic Steps:
| # Check container status
docker-compose ps
# View application logs
make logs SERVICE=invoiceninja-application.application
# Check configuration
docker-compose config
# Verify environment variables
docker-compose exec invoiceninja-application.application env | grep APP_
|
Common Causes and Solutions:
- Missing APP_KEY
| # Generate application key
make run CMD="php artisan key:generate"
# Verify key is set
grep APP_KEY .env
|
- Database Connection Failed
| # Verify database is running
docker-compose ps invoiceninja-application.mariadb
# Test database connectivity
docker-compose exec invoiceninja-application.mariadb mariadb \
--socket=/var/run/mysqld/mysqld.sock \
--user=invoiceninja --password=invoiceninja \
--execute="SELECT 1;"
# Check database credentials in .env
grep DB_ .env
|
- Permission Issues
| # Fix file permissions
docker-compose exec invoiceninja-application.application chown -R www-data:www-data /var/www/html/storage
docker-compose exec invoiceninja-application.application chmod -R 755 /var/www/html/storage
|
Application Responds Slowly
Symptoms:
- Page load times > 5 seconds
- Timeout errors
- High CPU usage
Diagnostic Steps:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | # Check resource usage
docker stats
# Monitor application performance
curl -w "@curl-format.txt" -o /dev/null -s http://localhost:8080/
# Check queue status
make run CMD="php artisan queue:work --once"
# Review slow queries
docker-compose exec invoiceninja-application.mariadb mariadb \
--socket=/var/run/mysqld/mysqld.sock \
--user=invoiceninja --password=invoiceninja \
--database=invoiceninja \
--execute="
SELECT
sql_text,
count_star,
avg_timer_wait/1000000000 as avg_seconds
FROM performance_schema.events_statements_summary_by_digest
ORDER BY avg_timer_wait DESC
LIMIT 10;
"
|
Solutions:
- Clear Application Cache
| make run CMD="php artisan cache:clear"
make run CMD="php artisan config:clear"
make run CMD="php artisan route:clear"
make run CMD="php artisan view:clear"
|
- Optimize for Production
| make run CMD="php artisan config:cache"
make run CMD="php artisan route:cache"
make run CMD="php artisan view:cache"
|
- Increase Resource Limits
Edit docker-compose.yml:
| services:
invoiceninja-application.application:
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
|
Error 500 - Internal Server Error
Symptoms:
- Application returns HTTP 500
- White page with no content
- Generic error message
Diagnostic Steps:
| # Enable debug mode temporarily
sed -i 's/APP_DEBUG=false/APP_DEBUG=true/' .env
docker-compose restart invoiceninja-application.application
# Check Laravel logs
make run CMD="tail -f storage/logs/laravel.log"
# Check PHP error log
docker-compose logs invoiceninja-application.application | grep -i error
|
Common Solutions:
- Fix Storage Permissions
| make run CMD="chmod -R 755 storage"
make run CMD="chmod -R 755 bootstrap/cache"
|
- Check Database Schema
| make run CMD="php artisan migrate:status"
make run CMD="php artisan migrate"
|
- Clear and Regenerate Caches
| make run CMD="php artisan cache:clear"
make run CMD="php artisan config:cache"
|
Important: Disable debug mode after troubleshooting:
| sed -i 's/APP_DEBUG=true/APP_DEBUG=false/' .env
docker-compose restart invoiceninja-application.application
|
Database Issues
Database Connection Refused
Symptoms:
- "Connection refused" errors
- Database container not running
- Application can't connect to database
Diagnostic Steps:
| # Check database container status
docker-compose ps invoiceninja-application.mariadb
# Check database logs
make logs SERVICE=invoiceninja-application.mariadb
# Test connection from application container
docker-compose exec invoiceninja-application.application nc -zv invoiceninja-application.mariadb 3306
|
Solutions:
- Restart Database Service
| docker-compose restart invoiceninja-application.mariadb
# Wait for database to be ready
sleep 15
docker-compose exec invoiceninja-application.mariadb mariadb \
--socket=/var/run/mysqld/mysqld.sock \
--user=invoiceninja --password=invoiceninja \
--execute="SELECT 1;"
|
- Check Network Connectivity
| # Verify network exists
docker network inspect webgrip
# Recreate network if needed
docker network create webgrip
|
- Verify Database Credentials
| # Check environment variables
grep DB_ .env
# Test manual connection
docker-compose exec invoiceninja-application.mariadb mariadb \
--socket=/var/run/mysqld/mysqld.sock \
--user=invoiceninja --password=invoiceninja \
--database=invoiceninja \
--execute="SELECT VERSION();"
|
Symptoms:
- Slow query responses
- High database CPU usage
- Connection timeouts
Diagnostic Steps:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 | # Check database performance
docker-compose exec invoiceninja-application.mariadb mariadb \
--socket=/var/run/mysqld/mysqld.sock \
--user=invoiceninja --password=invoiceninja \
--database=invoiceninja \
--execute="
SELECT
table_schema,
table_name,
table_rows,
data_length,
index_length
FROM information_schema.tables
WHERE table_schema = 'invoiceninja'
ORDER BY data_length DESC;
"
# Monitor active connections
docker-compose exec invoiceninja-application.mariadb mariadb \
--socket=/var/run/mysqld/mysqld.sock \
--user=invoiceninja --password=invoiceninja \
--database=invoiceninja \
--execute="SHOW PROCESSLIST;"
"
|
Solutions:
- Optimize Database
1
2
3
4
5
6
7
8
9
10
11
12
13 | # Analyze tables
docker-compose exec invoiceninja-application.mariadb mariadb \
--socket=/var/run/mysqld/mysqld.sock \
--user=invoiceninja --password=invoiceninja \
--database=invoiceninja \
--execute="ANALYZE TABLE invoices, clients, products;"
# Optimize database
docker-compose exec invoiceninja-application.mariadb mariadb \
--socket=/var/run/mysqld/mysqld.sock \
--user=invoiceninja --password=invoiceninja \
--database=invoiceninja \
--execute="OPTIMIZE TABLE invoices, clients, products;"
|
- Add Missing Indexes
| # Identify missing indexes
make run CMD="php artisan db:show --counts"
# Run migrations to add indexes
make run CMD="php artisan migrate"
|
- Increase Database Resources
Edit docker-compose.yml:
| services:
invoiceninja-application.mariadb:
environment:
- MARIADB_INNODB_BUFFER_POOL_SIZE=256M
- MARIADB_INNODB_LOG_FILE_SIZE=64M
deploy:
resources:
limits:
memory: 2G
|
Database Corruption
Symptoms:
- Database container won't start
- Data integrity errors
- Corrupted data files
Diagnostic Steps:
1
2
3
4
5
6
7
8
9
10
11
12 | # Check database logs for corruption
make logs SERVICE=invoiceninja-application.mariadb | grep -i corrupt
# Check filesystem
docker run --rm -v invoiceninja-application-mariadb-data:/data busybox ls -la /data
# Verify database integrity
docker-compose exec invoiceninja-application.mariadb mariadb \
--socket=/var/run/mysqld/mysqld.sock \
--user=invoiceninja --password=invoiceninja \
--database=invoiceninja \
--execute="CHECK TABLE invoices, clients, products;"
|
Recovery Steps:
- Stop Services
- Attempt Database Repair
1
2
3
4
5
6
7
8
9
10
11
12 | # Start database in recovery mode
docker run --rm -it \
-v invoiceninja-application-mariadb-data:/var/lib/mysql \
mariadb:12.0.2-noble mariadb \
--socket=/var/run/mysqld/mysqld.sock \
--user=root --password=root \
invoiceninja
# Check for corruption and repair
# In MariaDB shell:
# CHECK TABLE invoices, clients, products;
# REPAIR TABLE invoices, clients, products;
|
- Restore from Backup
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | # Remove corrupted data
docker volume rm invoiceninja-application-mariadb-data
# Create new volume
docker volume create invoiceninja-application-mariadb-data
# Start database
docker-compose up -d invoiceninja-application.mariadb
sleep 15
# Restore from backup
gunzip -c backups/latest/database.sql.gz | \
docker-compose exec -T invoiceninja-application.mariadb \
mariadb --socket=/var/run/mysqld/mysqld.sock \
--user=invoiceninja --password=invoiceninja invoiceninja
|
Network and Connectivity Issues
Cannot Access Application
Symptoms:
- Browser shows "connection refused"
- Curl commands fail
- Application not reachable
Diagnostic Steps:
| # Check if application is listening
curl -f http://localhost:8080/health
# Verify port binding
docker-compose ps
netstat -tlnp | grep 8080
# Check firewall rules
sudo ufw status
sudo iptables -L
|
Solutions:
- Verify Port Configuration
Check docker-compose.yml:
| services:
invoiceninja-application.application:
ports:
- "127.0.0.1:8080:8080" # Correct binding
# Not: - "8080:8080" # This exposes on all interfaces
|
- Check Application Configuration
| # Verify APP_URL matches access URL
grep APP_URL .env
# Check for proxy configuration
grep -i proxy .env
|
- Network Troubleshooting
| # Test from host
curl -v http://localhost:8080/
# Test from within container network
docker run --rm --network webgrip busybox wget -qO- http://invoiceninja-application.application:8080/health
|
SSL/TLS Issues
Symptoms:
- Certificate errors
- Mixed content warnings
- HTTPS not working
Solutions:
- Configure Reverse Proxy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 | # Nginx configuration
server {
listen 443 ssl;
server_name invoiceninja.yourcompany.com;
ssl_certificate /path/to/certificate.crt;
ssl_certificate_key /path/to/private.key;
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;
}
}
|
- Update Application Configuration
| # Update .env for HTTPS
sed -i 's|APP_URL=http://|APP_URL=https://|' .env
docker-compose restart invoiceninja-application.application
|
High Memory Usage
Symptoms:
- Container memory usage > 90%
- Out of memory errors
- Application crashes
Diagnostic Steps:
| # Monitor memory usage
docker stats --no-stream
# Check PHP memory configuration
make run CMD="php -i | grep memory_limit"
# Monitor application memory usage
make run CMD="php artisan tinker"
# In tinker: echo memory_get_usage(true);
|
Solutions:
- Increase Memory Limits
Edit docker-compose.yml:
| services:
invoiceninja-application.application:
deploy:
resources:
limits:
memory: 2G
|
- Optimize PHP Configuration
Create custom PHP configuration:
| # ops/docker/application/php.ini
memory_limit = 512M
max_execution_time = 300
upload_max_filesize = 100M
post_max_size = 100M
|
- Clear Memory Leaks
| # Restart application
docker-compose restart invoiceninja-application.application
# Clear all caches
make run CMD="php artisan cache:clear"
make run CMD="php artisan queue:restart"
|
High CPU Usage
Symptoms:
- CPU usage consistently > 80%
- Slow response times
- Queue processing delays
Diagnostic Steps:
| # Monitor CPU usage
docker stats
# Check for runaway processes
docker-compose exec invoiceninja-application.application top
# Monitor queue workers
make run CMD="php artisan queue:work --once"
|
Solutions:
- Optimize Queue Processing
| # Process queues in background
make run CMD="php artisan queue:work --daemon" &
# Clear failed jobs
make run CMD="php artisan queue:flush"
|
- Scale Resources
| # docker-compose.yml
services:
invoiceninja-application.application:
deploy:
resources:
limits:
cpus: '2.0'
reservations:
cpus: '1.0'
|
Container and Docker Issues
Symptoms:
- Container status shows "Exited (1)"
- Service doesn't stay running
- Restart loop
Diagnostic Steps:
| # Check exit status
docker-compose ps
# View container logs
docker-compose logs invoiceninja-application.application
# Run container interactively
docker-compose run --rm invoiceninja-application.application /bin/bash
|
Solutions:
- Fix Entrypoint Script
| # Check if entrypoint script is executable
docker-compose run --rm invoiceninja-application.application ls -la /entrypoint.sh
# Make executable if needed
docker-compose exec invoiceninja-application.application chmod +x /entrypoint.sh
|
- Verify Dependencies
| # Check if required files exist
docker-compose run --rm invoiceninja-application.application ls -la /var/www/html
# Verify PHP configuration
docker-compose run --rm invoiceninja-application.application php --version
|
Image Build Failures
Symptoms:
- Docker build fails
- Missing dependencies
- Build context issues
Solutions:
- Clear Build Cache
| # Remove build cache
docker system prune -f
docker-compose build --no-cache
|
- Check Dockerfile
| # Validate Dockerfile syntax
docker run --rm -i hadolint/hadolint < ops/docker/application/Dockerfile
|
- Verify Build Context
| # Check .dockerignore
cat .dockerignore
# Verify required files are present
ls -la ops/docker/application/
|
Common Deployment Scenarios
Scenario 1: Fresh Installation on New Server
Situation: Installing Invoice Ninja on a new server for the first time.
Step-by-Step Solution:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 | # 1. Install prerequisites
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
# Log out and back in for group changes to take effect
# 2. Clone repository
git clone https://github.com/webgrip/invoiceninja-application.git
cd invoiceninja-application
# 3. Configure environment
cp .env.example .env
nano .env # Edit with your settings
# 4. Set required variables
# - DB_PASSWORD=<strong-password>
# - DB_ROOT_PASSWORD=<strong-root-password>
# - SUBDOMAIN=invoiceninja
# - DOMAIN_NAME=yourcompany.com
# 5. Generate application key
make run CMD="php artisan key:generate"
# 6. Start services
make start
# 7. Wait for services to be ready
make wait-ready URL=http://localhost:8080/health
# 8. Complete web-based setup
# Navigate to http://localhost:8080/setup
|
Scenario 2: Migrating from Another Server
Situation: Moving existing Invoice Ninja installation to new server.
Step-by-Step Solution:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 | # On old server:
# 1. Create backup
./backup.sh
# 2. Transfer backup to new server
scp -r backups/latest/ user@newserver:/path/to/invoiceninja-application/backups/
# On new server:
# 3. Install and configure (steps 1-4 from Scenario 1)
# 4. Restore database
docker-compose up -d invoiceninja-application.mariadb
sleep 15
# Restore database securely: avoid passing the password on the command line.
# Option 1: Prompt for password interactively (recommended)
gunzip -c backups/latest/database.sql.gz | \
docker-compose exec -T invoiceninja-application.mariadb \
mariadb --socket=/var/run/mysqld/mysqld.sock \
--user=invoiceninja --password invoiceninja
# Option 2: Use the MARIADB_PWD environment variable for non-interactive use (less secure)
# export MARIADB_PWD='<password>'
# gunzip -c backups/latest/database.sql.gz | \
# docker-compose exec -e MARIADB_PWD -T invoiceninja-application.mariadb \
# mariadb --socket=/var/run/mysqld/mysqld.sock \
# --user=invoiceninja invoiceninja
# 5. Restore application data
docker volume rm invoiceninja-application-application-public-data
docker volume create invoiceninja-application-application-public-data
docker run --rm -v invoiceninja-application-application-public-data:/data \
-v $(pwd)/backups/latest:/backup \
busybox tar xzf /backup/application-data.tar.gz -C /data
# 6. Start all services
make start
# 7. Verify migration
curl -f http://localhost:8080/health
|
Scenario 3: Upgrading Invoice Ninja Version
Situation: Updating to a newer version of Invoice Ninja.
Step-by-Step Solution:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 | # 1. Create backup before upgrade
./backup.sh
# 2. Stop services
make stop
# 3. Update base image version in Dockerfile
nano ops/docker/application/Dockerfile
# Change: FROM invoiceninja/invoiceninja:5.12.27
# To: FROM invoiceninja/invoiceninja:5.13.0 # (example new version)
# 4. Rebuild images
docker-compose build --no-cache invoiceninja-application.application
# 5. Start services
make start
# 6. Run database migrations
make run CMD="php artisan migrate --force"
# 7. Clear caches
make run CMD="php artisan config:clear"
make run CMD="php artisan cache:clear"
make run CMD="php artisan view:clear"
# 8. Verify upgrade
curl -f http://localhost:8080/health
make logs SERVICE=invoiceninja-application.application | grep -i version
# 9. If issues occur, rollback
# git checkout HEAD~1 -- ops/docker/application/Dockerfile
# docker-compose build --no-cache
# make start
|
Scenario 4: Switching from MariaDB to PostgreSQL
Situation: Changing database backend from MariaDB to PostgreSQL.
Step-by-Step Solution:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 | # 1. Export data from MariaDB
docker-compose exec invoiceninja-application.mariadb mariadb-dump \
--socket=/var/run/mysqld/mysqld.sock \
--user=invoiceninja --password=<password> \
invoiceninja > migration-backup.sql
# 2. Stop services
make stop
# 3. Enable PostgreSQL in docker-compose.yml
# Uncomment the postgres service section
# 4. Update .env
nano .env
# Change:
# DB_CONNECTION=mysql → DB_CONNECTION=pgsql
# DB_HOST=invoiceninja-application.mariadb → DB_HOST=invoiceninja-application.postgres
# DB_PORT=3306 → DB_PORT=5432
# 5. Start PostgreSQL
docker-compose up -d invoiceninja-application.postgres
# 6. Convert and import data (requires pgloader)
# Note: This is complex - consider using migration tools or starting fresh
# 7. Start application
make start
# 8. Verify database connection
make run CMD="php artisan migrate:status"
|
Scenario 5: Recovering from Failed Update
Situation: Update failed and application is not working.
Step-by-Step Solution:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 | # 1. Stop all services
make stop
# 2. Check Docker logs for errors
docker-compose logs --tail=100
# 3. Restore from last known good backup
LATEST_BACKUP=$(ls -1d backups/backup_* | tail -2 | head -1)
echo "Restoring from: $LATEST_BACKUP"
# 4. Restore database
docker volume rm invoiceninja-application-mariadb-data
docker volume create invoiceninja-application-mariadb-data
docker-compose up -d invoiceninja-application.mariadb
sleep 15
gunzip -c "$LATEST_BACKUP/database.sql.gz" | \
docker-compose exec -T invoiceninja-application.mariadb \
mariadb --socket=/var/run/mysqld/mysqld.sock \
--user=invoiceninja --password=<password> invoiceninja
# 5. Restore application data
docker volume rm invoiceninja-application-application-public-data
docker volume create invoiceninja-application-application-public-data
docker run --rm -v invoiceninja-application-application-public-data:/data \
-v $(pwd)/$LATEST_BACKUP:/backup \
busybox tar xzf /backup/application-data.tar.gz -C /data
# 6. Revert code changes
git log --oneline -10 # Find last good commit
git reset --hard <commit-hash>
# 7. Rebuild and start
docker-compose build
make start
# 8. Verify recovery
make wait-ready URL=http://localhost:8080/health
|
Configuration Issues
Environment Variables Not Applied
Symptoms:
- Configuration changes don't take effect
- Application uses default values
- Settings not persisted
Solutions:
- Restart After Configuration Changes
| # Always restart after .env changes
docker-compose restart invoiceninja-application.application
# Verify environment variables
docker-compose exec invoiceninja-application.application env | grep APP_
|
- Clear Configuration Cache
| make run CMD="php artisan config:clear"
make run CMD="php artisan config:cache"
|
- Validate Configuration Format
| # Check .env syntax
cat .env | grep -v '^#' | grep -v '^$'
# Validate docker-compose.yml
docker-compose config
|
Email Configuration Issues
Symptoms:
- Emails not being sent
- SMTP authentication failures
- Mail queue backing up
Diagnostic Steps:
| # Test mail configuration
make run CMD="php artisan tinker"
# In tinker: Mail::raw('Test email', function($msg) { $msg->to('test@example.com')->subject('Test'); });
# Check mail queue
make run CMD="php artisan queue:work --once"
# View mail logs
docker-compose logs invoiceninja-application.application | grep -i mail
|
Solutions:
- Verify SMTP Settings
| # Check mail configuration
grep MAIL_ .env
# Test SMTP connection
telnet your-smtp-server.com 587
|
- Configure Mail Queue
| # Process mail queue
make run CMD="php artisan queue:work --queue=mail --once"
# Clear failed mail jobs
make run CMD="php artisan queue:flush"
|
Emergency Recovery Procedures
Complete System Recovery
When all else fails:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 | # 1. Stop all services
make stop
# 2. Backup current state
mkdir -p emergency-backup
docker run --rm -v invoiceninja-application-mariadb-data:/data -v $(pwd)/emergency-backup:/backup busybox cp -a /data/. /backup/
# 3. Reset to known good state
git checkout HEAD~1 -- docker-compose.yml .env
# 4. Pull fresh images
docker-compose pull
# 5. Start services
make start
# 6. Verify health
make wait-ready URL=http://localhost:8080/health
|
Data Recovery
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 | # Restore from latest backup
LATEST_BACKUP=$(ls -1 backups/ | tail -1)
echo "Restoring from: $LATEST_BACKUP"
# Stop services
make stop
# Restore database
docker volume rm invoiceninja-application-mariadb-data
docker volume create invoiceninja-application-mariadb-data
docker-compose up -d invoiceninja-application.mariadb
sleep 15
gunzip -c "backups/$LATEST_BACKUP/database.sql.gz" | \
docker-compose exec -T invoiceninja-application.mariadb \
mariadb --socket=/var/run/mysqld/mysqld.sock \
--user=invoiceninja --password=invoiceninja invoiceninja
# Restore application data
docker volume rm invoiceninja-application-application-data
docker volume create invoiceninja-application-application-data
docker run --rm -v invoiceninja-application-application-data:/data \
-v $(pwd)/backups/$LATEST_BACKUP:/backup \
busybox tar xzf /backup/application-data.tar.gz -C /data
# Start all services
make start
|
Sources
Troubleshooting procedures are based on common issues and solutions from Invoice Ninja community and Docker best practices:
- Invoice Ninja Community Support, https://invoiceninja.github.io/, Retrieved 2025-11-23
- Laravel Debugging Documentation, https://laravel.com/docs/10.x/errors, Retrieved 2025-11-23
- Docker Troubleshooting Guide, https://docs.docker.com/config/containers/, Retrieved 2025-11-23
- PostgreSQL Common Problems, https://www.postgresql.org/docs/current/appendixes.html, Retrieved 2025-11-23
- MariaDB Knowledge Base, https://mariadb.com/kb/en/, Retrieved 2025-11-23