How to Deploy TaxHacker to Production: Complete Docker Self-Hosting Guide
Deploy TaxHacker to production using Docker Compose with two containers—a Next.js 15+ application and PostgreSQL 17—configured via environment variables parsed in lib/config.ts and exposed on port 7331.
TaxHacker is a self-hosted, AI-powered accounting application maintained in the vas3k/TaxHacker repository. When you deploy TaxHacker to production, you run a containerized stack orchestrated by Docker, with all sensitive configuration centralized and validated through a Zod schema in lib/config.ts.
Production Architecture Overview
TaxHacker runs as a multi-container system designed for reproducible deployments. The architecture consists of a Next.js application server and a PostgreSQL database, connected via Prisma ORM.
The Application Stack
The app container runs the Next.js 15+ server built from the multi-stage Dockerfile. The build process uses node:23-slim as a base, installs openssl (required for Prisma), and bundles runtime dependencies including ghostscript and graphicsmagick for PDF and image processing. The production stage copies only built artifacts and runs docker-entrypoint.sh, which executes database migrations before starting the server on port 7331.
The postgres container runs PostgreSQL 17 using the official image, persisting data to a Docker volume. You can replace this with an external database by modifying the DATABASE_URL environment variable.
Configuration Management
All production settings derive from environment variables defined in .env.example and strictly parsed by the Zod schema in lib/config.ts (lines 3–23). This file exports a type-safe config object used throughout the application for AI provider keys (OPENAI_API_KEY, GOOGLE_API_KEY, MISTRAL_API_KEY), authentication secrets (BETTER_AUTH_SECRET), and infrastructure paths (UPLOAD_PATH).
Deployment Methods
You can deploy TaxHacker using three approaches depending on your infrastructure requirements: quick start with pre-built images, building from source, or a hardened production configuration.
Method 1: Quick Start with Docker Compose
The fastest way to deploy TaxHacker to production uses the provided docker-compose.yml file, which pulls the pre-built image from GitHub Container Registry.
# Download the compose configuration
curl -O https://raw.githubusercontent.com/vas3k/TaxHacker/main/docker-compose.yml
# Create environment variables
cat > .env <<EOF
SELF_HOSTED_MODE=true
UPLOAD_PATH=./data/uploads
DATABASE_URL=postgresql://postgres:postgres@postgres:5432/taxhacker
BETTER_AUTH_SECRET=$(openssl rand -base64 32)
OPENAI_API_KEY=sk-your-key-here
EOF
# Deploy the stack
docker compose up -d
This command starts both containers, binds the application to port 7331, and automatically initializes the database using the entrypoint script at docker-entrypoint.sh.
Method 2: Building from Source
For custom modifications or air-gapped environments, build the image locally from the Dockerfile:
git clone https://github.com/vas3k/TaxHacker.git
cd TaxHacker
docker build -t taxhacker:custom .
docker run -d \
-p 7331:7331 \
-e SELF_HOSTED_MODE=true \
-e DATABASE_URL=postgresql://user:pass@host:5432/taxhacker \
-e BETTER_AUTH_SECRET=$(openssl rand -base64 32) \
--name taxhacker_app taxhacker:custom
The Dockerfile implements a multi-stage build that minimizes the final image size by separating the build environment (requiring openssl and dev dependencies) from the production runtime.
Method 3: Production-Grade Deployment
For public-facing deployments behind a reverse proxy, use docker-compose.production.yml:
curl -O https://raw.githubusercontent.com/vas3k/TaxHacker/main/docker-compose.production.yml
# Edit .env to set SELF_HOSTED_MODE=false and BASE_URL=https://your-domain.com
docker compose -f docker-compose.production.yml up -d
Key differences from the quick-start method:
SELF_HOSTED_MODEis set tofalse, disabling the auto-login shortcut for security- The container binds to
127.0.0.1:7331only, requiring an external reverse proxy (Nginx, Traefik, or Caddy) for TLS termination - External environment files are strictly enforced via
env_file:declarations
Database Initialization and Migrations
The Prisma ORM handles schema management through lib/db.ts, which exports a singleton client with connection pooling. Migrations run automatically when the container starts via docker-entrypoint.sh, which executes:
npx prisma migrate deploy
To manually trigger a migration in a running container:
docker exec -it taxhacker_app npx prisma migrate deploy
The schema definition in prisma/schema.prisma defines tables for users, transactions, uploaded files, and application settings, which are created automatically on first run.
Required Environment Configuration
Before deploying TaxHacker to production, populate your .env file based on .env.example with these critical variables:
BETTER_AUTH_SECRET: A random string of at least 16 characters for password-less authentication encryptionDATABASE_URL: PostgreSQL connection string (e.g.,postgresql://postgres:postgres@postgres:5432/taxhacker)UPLOAD_PATH: Absolute path for persistent file storage (e.g.,/app/data/uploads)OPENAI_API_KEY,GOOGLE_API_KEY, orMISTRAL_API_KEY: Required only if using AI-powered document extractionRESEND_API_KEYandRESEND_FROM_EMAIL: Required for transactional email delivery in productionSTRIPE_SECRET_KEYandSTRIPE_WEBHOOK_SECRET: Required only if operating as a paid SaaS
These values are validated at runtime by the Zod schema in lib/config.ts, which throws explicit errors if required variables are missing or malformed.
Security and Operations Checklist
Complete these steps before exposing TaxHacker to public traffic:
- Generate a secure
BETTER_AUTH_SECRETusingopenssl rand -base64 32 - Configure TLS termination at your reverse proxy; the container serves plain HTTP on port 7331
- Back up the PostgreSQL volume regularly (the
pgdatavolume in Docker Compose) - Set appropriate AI rate limits in
next.config.tsif exposing to multiple users - Verify file upload permissions on the
UPLOAD_PATHdirectory to prevent unauthorized access
Summary
- Deploy TaxHacker to production using Docker Compose with the official
ghcr.io/vas3k/taxhacker:latestimage or a custom build from theDockerfile - Run two containers: a Next.js 15+
appcontainer and a PostgreSQL 17postgrescontainer - Configure via
lib/config.ts: Validate all settings through environment variables using the.env.exampletemplate - Expose port 7331: Bind to localhost for production deployments behind a reverse proxy, or directly for private networks
- Initialize automatically: Database migrations run via
docker-entrypoint.shon container startup - Enable AI features: Provide OpenAI, Gemini, or Mistral API keys for automatic document parsing
Frequently Asked Questions
What ports and protocols does TaxHacker require?
TaxHacker exposes port 7331 over HTTP. You must place it behind a reverse proxy such as Nginx or Traefik to handle TLS/HTTPS termination in production. PostgreSQL communicates over port 5432 internally within the Docker network.
Can I use an external database instead of the Docker PostgreSQL container?
Yes. Set DATABASE_URL to point to your external PostgreSQL 17 instance (e.g., AWS RDS or Supabase) and remove the postgres service from your docker-compose.yml. Ensure the database is accessible from the TaxHacker container and that credentials match the format postgresql://user:password@host:port/database.
How do I upgrade to a new version of TaxHacker?
Pull the latest image (docker pull ghcr.io/vas3k/taxhacker:latest) or rebuild your custom image from the updated repository. Stop the containers, run docker compose up -d to restart, and the docker-entrypoint.sh script will automatically apply any pending database migrations via Prisma before starting the application.
Is a GPU required for the AI document extraction features?
No. TaxHacker uses cloud-based AI providers (OpenAI, Google Gemini, or Mistral) via API calls defined in lib/config.ts. The server itself runs on standard CPU resources, though you must provide valid API keys for the respective providers to enable automatic receipt and invoice parsing.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →