--- title: "Nginx Proxy Manager — Admin Password Reset via SQLite bcrypt Injection" aliases: [npm-admin-reset, npm-password-reset, npm-sqlite-reset] tags: [nginx-proxy-manager, npm, sqlite, homelab, docker, admin] sources: - "daily/2026-04-29.md" created: 2026-04-29 updated: 2026-04-29 --- # Nginx Proxy Manager — Admin Password Reset via SQLite bcrypt Injection When locked out of Nginx Proxy Manager (NPM), the admin password can be reset by directly modifying the SQLite database. NPM stores user credentials in a `database.sqlite` file. The process requires stopping NPM first to prevent data corruption, generating a bcrypt hash of the new password, and writing it into the `auth` table. ## Key Points - **NPM must be stopped before editing the DB** — modifying a live SQLite file risks corruption - **Always back up the database first** — `cp database.sqlite database.sqlite.bak.YYYY-MM-DD` - **Password is stored as a bcrypt hash** in the `auth` table - **Restart NPM after the edit** — NPM reads credentials from the DB at runtime - **Default admin email** is typically `admin@example.com`; in this homelab it is `admin@ai-impress.com` ## Details ### Step-by-Step Reset Process ```bash # 1. Stop NPM to prevent corruption docker compose stop npm # 2. Navigate to the NPM data directory cd /opt/npm/data # 3. Back up the database cp database.sqlite database.sqlite.bak.$(date +%Y-%m-%d) # 4. Generate a bcrypt hash for the new password # Option A: Python python3 -c "import bcrypt; print(bcrypt.hashpw(b'admin', bcrypt.gensalt(rounds=10)).decode())" # Option B: Node.js (if available) node -e "const bcrypt = require('bcrypt'); bcrypt.hash('admin', 10).then(h => console.log(h))" # Option C: use htpasswd htpasswd -bnBC 10 "" admin | tr -d ':\n' # 5. Open the database sqlite3 database.sqlite # 6. Find the admin user row SELECT id, name, email FROM user; -- or, depending on NPM version: SELECT id, name, email FROM auth; # 7. Update the password hash UPDATE auth SET secret = '$2b$10$YOUR_BCRYPT_HASH_HERE' WHERE identity = 'admin@ai-impress.com'; -- or if the table is named 'user': UPDATE user SET password = '$2b$10$YOUR_BCRYPT_HASH_HERE' WHERE email = 'admin@ai-impress.com'; # 8. Verify SELECT identity, secret FROM auth; # 9. Exit and restart NPM .quit docker compose start npm ``` ### Table Structure Notes NPM's SQLite schema varies slightly between versions. In most installations: - Table `auth` contains columns: `id`, `identity` (email), `secret` (bcrypt hash), `type` - Table `user` contains: `id`, `name`, `email`, `password` Run `.tables` and `PRAGMA table_info(auth);` inside sqlite3 to confirm the structure for your version before updating. ### Why NPM Must Be Stopped SQLite uses file-level locking. NPM holds a write lock on `database.sqlite` while running. Editing the file while NPM is active can corrupt the WAL (write-ahead log) or leave the DB in an inconsistent state. Always stop the container, edit, then restart. ### Homelab Context This procedure was used when the NPM admin account at `admin@ai-impress.com` became inaccessible. Password was reset to `admin` (minimum viable for internal homelab use). NPM fronts all internal services via reverse proxy and SSL termination at `/opt/npm/`. ## Related Concepts - [[wiki/concepts/adguard-dns-rewrites-homelab]] — AdGuard DNS rewrites pointing *.ai-impress.com to NPM's IP - [[wiki/concepts/authentik-homelab-tradeoffs]] — NPM auth_request integration removed when Authentik was retired - [[wiki/concepts/prowlarr-flaresolverr-get-only]] — similar SQLite direct-edit pattern for Prowlarr cookie injection - [[wiki/homelab/_index]] — homelab infrastructure; NPM as reverse proxy gateway ## Sources - [[daily/2026-04-29.md]] — NPM lockout; database.sqlite backup; bcrypt hash injection into auth table; email admin@ai-impress.com; password reset to "admin"; NPM must be stopped during edit