Repository navigation
Getting Started
Two supported setups: fully local and demo-compatible. pnpm setup asks which one you want, writes a working .env, and can run the remaining commands for you. Everything on this page is what it does, in case you would rather do it by hand.
Prerequisites: Node 22+, pnpm 11+. Docker for the fully local path. These are enforced (engines plus engine-strict), so an unsupported runtime fails at install with a clear message instead of somewhere confusing later.
git clone https://github.com/Anonify-v2-0/Anonify2.0.git && cd Anonify2.0
pnpm install
pnpm setuppnpm setup asks:
- How to run it: fully local, or demo-compatible.
-
Who can reach it: just you (
--private), or public and shared (--public). - Which services: Postgres / RustFS / Tesseract, or Neon / Vercel Blob / Mistral.
- Which AI provider and model, if any: it discovers models, pages and searches large catalogs, shows advertised capabilities (and list prices where the provider publishes them), and verifies the model with two synthetic requests before saving. See AI Providers.
- What the limits should be: quotas, rate limits, email parser limits, attachment and mailbox expansion.
- Whether to keep the secrets already in
.env.
Who can reach it is a separate question from which services you use, because they are separate facts: a self-hosted instance on Neon is still your instance and gets your allowances. Answer "just me" and there are no daily quotas at all. Answer "public and shared" and one visitor's workbook stops being everyone's budget.
Every default it prints is read from the code that enforces it, so what you see is what is in force. Anything you leave alone is written into .env as a commented line, so the file says what the default is instead of leaving it to be discovered. Sizes are asked for and written as sizes (32MB, 512KB, 1.5GB), never as byte counts. A plain number is still read as bytes, so an existing .env keeps working.
At the end, setup offers to run what comes next: start Postgres and RustFS, migrate, warm OCR and start the app on the host, or run everything in Docker. It never mixes the two, because the app container would already hold the port pnpm dev wants. Each command is shown before it runs and runs only on an explicit choice. A failure offers retry, skip or stop, and stopping prints exactly the commands that did not run.
pnpm setup --local --defaults --yes # no questions: local, profile defaults
pnpm setup --public # a shared instance: strict limits
pnpm setup --demo # the hosted demo's services
pnpm setup --force # overwrite .env without asking
pnpm setup --help # every flag--yes and non-interactive runs stay offline for AI: existing AI settings are kept, and no model discovery or billable probe happens. Run pnpm ai verify separately to verify a model in a script.
Re-running it is safe. It backs up the previous .env and offers to reuse the secrets already in it, which matters more than it sounds. Documents are sealed with per-document keys wrapped by ENCRYPTION_KEY, so a new key does not reset anything. It makes everything already stored permanently unreadable.
Postgres and RustFS (S3-compatible storage) run in Docker, OCR runs through Tesseract, and the optional model pass can run through Ollama, LM Studio or llama.cpp. No external service is involved at any point.
pnpm install
pnpm setup --local # generates the secrets; can start everything for you
docker compose up -d # Postgres, RustFS, migrations, then Anonify itself
# http://localhost:3000docker compose up -d runs the whole application. The app image is built from this repo, the schema is applied before the app starts, and nothing needs to be installed on the host beyond Docker. pnpm install and pnpm setup are there to write .env, which is where the encryption key and the fingerprint secret come from.
| Service | Port | Credentials | Purpose |
|---|---|---|---|
app |
3000 | none | Anonify, built from this repo |
postgres (Postgres 17) |
5432 |
anonify / anonify
|
the database, in place of Neon |
rustfs |
9000 (API), 9001 (console) |
anonify / anonify-dev-secret
|
S3-compatible storage, in place of Vercel Blob |
rustfs-volume-init |
none | none | gives the data volume to RustFS's user, then exits |
rustfs-init |
none | none | idempotently creates the anonify bucket, then exits |
migrate |
none | none | applies migrations and the workflow schema, then exits |
scheduler |
none | none |
opt-in expiry sweep (--profile scheduler); see Deployment
|
Every published port binds to 127.0.0.1 only, and data lives in named volumes across restarts. The credentials are development defaults. Do not reuse them anywhere reachable from outside your machine.
Port already taken? Set APP_PORT, POSTGRES_PORT, RUSTFS_PORT or RUSTFS_CONSOLE_PORT in .env. The addresses used inside the Compose network are fixed.
The app starts only after migrate exits successfully, so a fresh up never serves against an unapplied schema. The image is a Next.js standalone build on node:22-slim: Debian rather than Alpine, because sharp, @napi-rs/canvas and the pdf.js renderer ship native binaries. Durable runs live in Postgres through @workflow/world-postgres, and instrumentation.ts starts the worker that polls for jobs. Without that worker, uploads are accepted and never processed.
Upgrading from MinIO? The local stack moved to RustFS in 1.3.0 and reuses your existing
anonify_minio-datavolume. The import is one-way, so back the volume up first. See Upgrading.
Start only the dependencies, so port 3000 stays free:
docker compose up -d postgres rustfs rustfs-init
pnpm db:migrate # apply the schema
pnpm ocr:warm # optional: fetch the OCR model now rather than on the first scan
pnpm dev # http://localhost:3000ANONIFY_PROFILE=self-hosted
DATABASE_URL=postgresql://anonify:anonify@localhost:5432/anonify
DATABASE_DRIVER=postgres
STORAGE_DRIVER=s3
S3_ENDPOINT=http://localhost:9000
S3_BUCKET=anonify
S3_ACCESS_KEY_ID=anonify
S3_SECRET_ACCESS_KEY=anonify-dev-secret
OCR_PROVIDER=tesseract
ENCRYPTION_KEY=... # generated by pnpm setup
FINGERPRINT_SECRET=... # generated by pnpm setup
# optional, a local model:
AI_PROVIDER=ollama
AI_MODEL=qwen3-vl:4b-instruct
AI_MODEL_CAPABILITIES=... # written by setup / pnpm ai verifyLeave STORAGE_DRIVER unset and uploads go to .anonify-storage/ on disk. You still need a Postgres somewhere, because the redaction record lives in it.
ollama pull qwen3-vl:4b-instruct # a small vision model CI also tests against
pnpm ai verify --provider ollama --model qwen3-vl:4b-instructpnpm setup --local offers the first local server it finds (Ollama, then LM Studio, then llama.cpp). With the app in Docker, localhost in OLLAMA_BASE_URL is mapped to the Docker host automatically. On Linux, Ollama must listen on an interface Docker can reach. Details: AI Providers §3.
pnpm install
pnpm setup --demo
# fill in the keys it lists
pnpm db:migrate
pnpm dev| Variable | Service | Needed for |
|---|---|---|
DATABASE_URL |
Neon | The database. Use the pooled string. |
BLOB_READ_WRITE_TOKEN |
Vercel Blob | Storage. The browser uploads directly to it. |
MISTRAL_API_KEY |
Mistral | OCR for scanned documents (OCR_PROVIDER=mistral). |
AI_GATEWAY_API_KEY |
Vercel AI Gateway | Optional: the contextual detection pass. |
CRON_SECRET |
your host | Gates the expiry sweep. |
ANONIFY_PROFILE=demo selects the strict rate limits and small daily quotas the shared demo runs with.
With no model configured, pattern detection, manual redaction, search, rules, learned rule offers and export all work. Only the contextual pass (names, prose addresses, roles) and Hush are unavailable, and the document says the model pass did not run. See Redaction Engine.
Tesseract downloads its model the first time it reads a scanned document (~2–13 MB depending on OCR_TESSERACT_MODEL) and caches it in .cache/tesseract (gitignored). pnpm ocr:warm fetches it during setup instead, so the wait comes at a moment when waiting is expected. In a container, point TESSERACT_CACHE_PATH at a mounted volume. Engine and model are separate choices: Configuration §4.
- Open
http://localhost:3000. - Drag in a file, or several (they become a batch, with one review pass and one download at the end), or a mailbox (one document per message).
- Pick a preset. It changes what is looked for and nothing else. See Redaction Presets.
- Wait for processing. Progress streams, and a closed tab does not cancel it.
-
Review. Accept or reject suggestions (grouped by value), click a word, drag across text or a region, redact a cell, row or column, search (
Ctrl/⌘+F) and Redact all, write a rule, or ask Hush (Ctrl/⌘+K). Nothing is removed that you did not accept. See Review Workspace. - Export. Choose a method per category (mask, pseudonymize, tokenize, encrypt), and optionally several copies. The artifact is re-opened and read adversarially before it is delivered. Beside it you get a report (counts, methods, what you declined, both checksums) and, for a reversible method, a vault that is shown once and stored nowhere. See Export and Anonymisation.
- Download. The link is signed, lasts five minutes, and is checksum-verified as it streams.
Documents expire after 1 h, 6 h, 24 h or 3 days (extendable up to 72 h from upload). A scheduled sweep then deletes the source, the normalized model, every export and the row. If you self-host, you have to run that sweep yourself: see Deployment.
-
CLI Reference: every
pnpmcommand - Configuration: every setting, and what it defaults to
- Supported Formats: what each format's redaction actually does
- Troubleshooting: when something goes wrong
Anonify: AI proposes, the application applies, and only what a person accepted is removed.
Repository · Report a bug · Request a feature · Security policy · Apache-2.0
This wiki describes v1.10.0 and summarises and links the in-repo documentation. Where the two disagree, the files under docs/, CHANGELOG.md and SECURITY.md are canonical.
Getting going
Using it
- Supported Formats
- Review Workspace
- Search and Rules
- Hush Assistant
- Redaction Presets
- Export and Anonymisation
- Batches and Mailboxes
How it works
- Architecture
- Processing Workflow
- Redaction Engine
- Storage and Encryption
- Streaming IO
- Data Model
- API Reference
- Security Model
When it breaks
Contributing
Repository · Issues · Releases · Changelog