Skip to main content

Getting Started

NullReport is a self-hosted, AI-assisted penetration-test report generator. You write your sections, track structured findings with CVSS, and export a polished, branded DOCX, all from one Docker stack on your own infrastructure. There's no cloud and no multi-tenancy, so your data stays on your machine.

In a hurry?

Clone the repo, set two secrets, and run docker compose up -d --build. Jump to Install and you'll be logged in within five minutes.

Choose your tier

Free
Pro
TeamMost popular
Price
$0
$39/mo
$99/mo + $30/seat
Users (seats)
1
1
3 (+ extra seats)
Reports
Unlimited
Unlimited
Unlimited
Finding-template library
DOCX export
Custom DOCX templates
1
Unlimited
Unlimited
AI drafting & polish
Roles (Admin / Editor / Viewer)
Comments & activity feed
Real-time collaboration

The tier is baked into the Docker image at build time (a TIER build argument). A Pro or Team license on a free image won't unlock anything, because the image and the license have to match. There's more on that in Licensing.

Need a custom seat count? Get in touch.

Prerequisites

  • Docker and Docker Compose (Docker Desktop on macOS/Windows includes both).
  • Two secrets you'll generate below: a JWT_SECRET and an ENCRYPTION_KEY.
  • Nothing else. Postgres runs as a container, so you don't install a database yourself.

Install

# 1. Clone
git clone https://github.com/izzy0101010101/nullreport.git
cd nullreport

# 2. Create your .env from the example
cp .env.docker.example .env

# 3. Generate the two required secrets
echo "JWT_SECRET=$(openssl rand -hex 32)" >> .env
echo "ENCRYPTION_KEY=$(openssl rand -hex 32)" >> .env

# 4. Pick a tier (free | pro | team) and bring it up.
# TIER selects which image is built.
TIER=free docker compose up -d --build

Then open http://localhost:3000.

Set real secrets before going live

JWT_SECRET signs login sessions and ENCRYPTION_KEY encrypts stored AI API keys with AES-256-GCM. ENCRYPTION_KEY must be exactly 64 hex characters (32 bytes), which openssl rand -hex 32 produces. The backend refuses to start with a malformed key. Use unique values per install and never commit them.

What happens on first boot

The database schema is created automatically, so there's nothing to migrate by hand.

First login

  1. On first boot the backend creates the admin account with a randomly generated password and prints it to the logs once. Grab it with:
    docker compose logs backend | grep -A1 "First run detected"
    (To pin a known password instead, set ADMIN_INITIAL_PASSWORD in your .env before the first boot.)
  2. Open http://localhost:3000 and log in:
    • Username: admin
    • Password: the value from the logs (or your ADMIN_INITIAL_PASSWORD)
  3. You're immediately required to set a new password (minimum 6 characters). This only happens once.
  4. You land on the Reports dashboard, already populated with a demo report so you have something to explore.
The login screen and the mandatory first-run password change.
Save the generated password

The first-run password is shown in the logs only once. Save it somewhere safe, complete the forced change on first login, and don't expose the app to the internet without a reverse proxy and TLS in front of it.

Activate a paid tier

Licensing is driven by the LICENSE_KEY environment variable. There's no in-app field for it. After purchasing, you'll receive a license key:

  1. Add it to your .env:

    LICENSE_KEY=NR-PRO-xxxxxxxx   # the key from your purchase email / portal
  2. Make sure your image tier matches the license (build or pull the pro or team image; see Install).

  3. Restart with docker compose up -d.

On startup the backend activates the key against the license server, caches a signed token, and unlocks the matching tier. Leaving LICENSE_KEY empty runs the free tier. Full details, including the offline grace period and machine binding, live in Licensing.

What ships out of the box

First boot seeds a working starting point:

  • A demo report, "Example: Acme Corp Web App Pentest", with sections and findings so you can see a complete report immediately.
  • A DOCX export template, the "Templating Showcase Template", ready to export against.
  • One example finding template, SQL Injection, to show the format. Build your own library from there.

Quick walkthrough

The fastest path from zero to a finished report:

From the Reports dashboard, click New Report, give it a title and client, pick the seeded report template, and click Create. See Reports.

Optional: local AI with Ollama

On Pro and Team, you can point the AI features at a local Ollama model instead of a cloud key. The repo ships a docker-compose.ollama.yml overlay that bundles Ollama and wires it up:

TIER=pro docker compose -f docker-compose.yml -f docker-compose.ollama.yml up -d --build

Data, backups, and updates

Your data lives in two Docker volumes, and you should back up both:

VolumeHolds
db-dataThe Postgres database (reports, findings, users, templates metadata)
app-data (/data)License cache, the machine instance ID, uploaded images, and DOCX template files

To update:

git pull
docker compose up -d --build # or `--pull always` for prebuilt images

Your volumes are preserved and the schema is reconciled automatically on startup.

Don't wipe the volumes on a licensed install

docker compose down -v deletes app-data, including the machine instance ID your license is bound to. After that, re-activation fails until you click Deactivate Machine in the license portal. See Licensing.

What's next