# Invoice Ninja **Type**: Invoicing & Billing Application **Domain**: https://invoice.hyperthrive.io **Version**: 5.12.28 **Architecture**: Official Docker stack from [invoiceninja/dockerfiles](https://github.com/invoiceninja/dockerfiles) **Deployment Date**: 2025-10-14 ## Architecture Invoice Ninja runs using the official Docker Compose stack with three services: 1. **invoiceninja-server-1** - Nginx web server (port 80 internal) 2. **invoiceninja-app-1** - Laravel application with supervisord (PHP-FPM, queue workers, scheduler) 3. **invoiceninja-db-1** - MariaDB 10.11 database ### Traefik Integration The nginx service connects to the external `traefik` network and uses labels for automatic SSL/routing: - **Domain**: invoice.hyperthrive.io - **Protocol**: HTTPS via Let's Encrypt - **Entry Point**: websecure (443) - **Internal Port**: 80 (nginx) ### Directory Structure (Server) ``` ~/services/invoiceninja/ ├── docker-compose.yml # Main compose file ├── env # Environment configuration ├── config/ │ └── nginx/ │ └── in-vhost.conf # Nginx vhost config ├── docker/ │ ├── app/ │ │ ├── public/ # Application public files (shared with nginx) │ │ └── storage/ # Application storage (logs, cache, uploads) │ └── mysql/ │ └── data/ # Database files ``` **Important**: The `docker/app/` directories must be owned by user `1500:1500` (the container's runtime user). ## Common Operations ### Check Status ```bash ssh jared@15.204.247.153 "docker ps --filter name=invoiceninja" ``` ### View Logs ```bash # Application logs ssh jared@15.204.247.153 "docker logs invoiceninja-app-1 --tail 50" # Database logs ssh jared@15.204.247.153 "docker logs invoiceninja-db-1 --tail 50" # Nginx logs ssh jared@15.204.247.153 "docker logs invoiceninja-server-1 --tail 50" ``` ### Update Invoice Ninja ```bash ssh jared@15.204.247.153 "cd ~/services/invoiceninja && \ docker compose pull && \ docker compose up -d && \ docker exec invoiceninja-app-1 php artisan migrate --force && \ docker exec invoiceninja-app-1 php artisan optimize" ``` ### Backup Database ```bash ssh jared@15.204.247.153 "cd ~/services/invoiceninja && \ docker compose exec -T db sh -c 'exec mysqldump --all-databases -uroot -p\"\$MYSQL_ROOT_PASSWORD\"' \ > ~/backups/invoiceninja-$(date +%Y%m%d-%H%M%S).sql" ``` ### Restore Database ```bash ssh jared@15.204.247.153 "cd ~/services/invoiceninja && \ docker compose exec -T db sh -c 'exec mysql -uroot -p\"\$MYSQL_ROOT_PASSWORD\"' \ < ~/backups/invoiceninja-TIMESTAMP.sql" ``` ### Restart Services ```bash ssh jared@15.204.247.153 "cd ~/services/invoiceninja && docker compose restart" ``` ### Run Artisan Commands ```bash # Generic pattern ssh jared@15.204.247.153 "docker exec invoiceninja-app-1 php artisan " # Examples ssh jared@15.204.247.153 "docker exec invoiceninja-app-1 php artisan queue:work" ssh jared@15.204.247.153 "docker exec invoiceninja-app-1 php artisan cache:clear" ssh jared@15.204.247.153 "docker exec invoiceninja-app-1 php artisan db:seed" ``` ## Key Configuration ### Environment Variables (env file) Critical settings in `~/services/invoiceninja/env`: - `APP_URL=https://invoice.hyperthrive.io` - Public URL - `APP_KEY=base64:...` - Encryption key (DO NOT change after initial setup) - `DB_HOST=db` - Database hostname (container name) - `MYSQL_ROOT_PASSWORD` - DB root password - `MYSQL_DATABASE=ninja` - Database name - `MYSQL_USER=ninja` - DB user - `MYSQL_PASSWORD` - DB password - `TRUSTED_PROXIES=*` - Trust Traefik proxy - `MAIL_MAILER=log` - Mail driver (currently logging only) ### Traefik Labels (docker-compose.yml) ```yaml labels: - "traefik.enable=true" - "traefik.http.routers.invoiceninja.rule=Host(`invoice.hyperthrive.io`)" - "traefik.http.routers.invoiceninja.entrypoints=websecure" - "traefik.http.routers.invoiceninja.tls.certresolver=letsencrypt" - "traefik.http.services.invoiceninja.loadbalancer.server.port=80" - "traefik.docker.network=traefik" ``` ## Troubleshooting ### Permission Denied Errors If the app container fails with "Permission denied" creating directories: ```bash ssh jared@15.204.247.153 "cd ~/services/invoiceninja && \ docker compose down && \ sudo chown -R 1500:1500 docker/app && \ docker compose up -d" ``` ### Database Connection Issues Check database is healthy: ```bash ssh jared@15.204.247.153 "docker inspect invoiceninja-db-1 --format='{{.State.Health.Status}}'" ``` Should return `healthy`. If not, check logs. ### 502 Bad Gateway Usually means the app container isn't running or PHP-FPM hasn't started: 1. Check app container status: `docker ps --filter name=invoiceninja-app-1` 2. Check app logs: `docker logs invoiceninja-app-1 --tail 100` 3. Look for PHP-FPM startup message: "ready to handle connections" ### SSL Certificate Issues Traefik automatically handles SSL. If certificate issues occur: 1. Check Traefik logs: `docker logs traefik` 2. Verify DNS points to server: `dig invoice.hyperthrive.io` 3. Check Traefik dashboard for router/certificate status ### Queue Not Processing The official stack includes queue workers via supervisord. Check they're running: ```bash ssh jared@15.204.247.153 "docker exec invoiceninja-app-1 supervisorctl status" ``` Should show `queue-worker_00` and `queue-worker_01` as RUNNING. ## Migration History This deployment uses the **official Invoice Ninja Docker stack** (as of 2025-10-14). Previous custom stack was replaced to align with upstream recommendations and simplify maintenance. **Pre-migration backup location**: `~/backups/invoiceninja-pre-official/` on server (retained until deployment proven stable) ## References - Official Docker Repository: https://github.com/invoiceninja/dockerfiles - Invoice Ninja Docs: https://invoiceninja.github.io - Server Profile: `profile.yaml` - Configuration Template: `configs/invoiceninja-official-template.yml`