Skip to content

Latest commit

 

History

46 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

lazynpmplus

A terminal UI (TUI) client for Nginx Proxy Manager and its NPMplus fork. Manage proxy hosts, redirections, streams, access lists and certificates over the REST API — straight from an SSH terminal, no web UI required.

License: MIT Go Version GHCR Docker Hub

Status: under active development.

Note: Built in pair-programming with AI assistance; the code is largely human-reviewed and tested.


Features

  • Terminal-native TUI — runs entirely in the terminal (over SSH, no web UI needed): responsive layout, keyboard-driven navigation, help overlay.
  • NPM-compatible — works with Nginx Proxy Manager and its NPMplus fork over the REST API; the variant is auto-detected (or force it with --variant).
  • Manage your reverse proxy — proxy hosts, redirections, dead (404) hosts, streams and access lists with full CRUD; browse users, the audit log and settings.
  • Certificate handling — issue Let's Encrypt certificates (HTTP & DNS challenge), upload custom certificates, renew and delete.
  • Multi-language ready — ships with English and Czech, built so more languages can be added with no code changes.

Quick start

lazynpmplus is an interactive TUI client (not a server), so it always needs a terminal — note the -it on docker run and the run --rm (not up) for compose.

a) Official images — recommended, no build

Pre-built multi-arch images (linux/amd64 + linux/arm64) are published on every release to two registries:

# Pull (either registry works):
docker pull ghcr.io/mwarcz/lazynpmplus:latest
# docker pull docker.io/mwarcz/lazynpmplus:latest

# Run against an existing NPM instance:
docker run --rm -it ghcr.io/mwarcz/lazynpmplus:latest \
  --server http://192.168.1.100:81 --identity admin@example.com

Available tags: latest, plus version tags such as v1.2.3, 1.2 and 1.

b) Docker compose — recommended full stack (NPM + lazynpmplus)

Run lazynpmplus alongside a complete Nginx Proxy Manager instance in one stack; the client reaches NPM over the internal network. See docker/compose/ for the full walkthrough.

docker compose -f docker/compose/inline-env/compose.yml up -d
docker compose -f docker/compose/inline-env/compose.yml run --rm lazynpmplus

The compose example ships three sub-variants that differ only in how the client is configured — pick the one that matches how you manage settings:

Variant Configure via Use when
inline-env/ environment: in compose.yml Quick demos; one file, nothing else to manage.
dotenv/ env_file: → local .env Keep credentials out of compose.yml / git.
config-file/ mounted lazynpmplus.yml You manage app config as versioned files.

c) From source

Requires Go ≥ 1.25.

git clone https://github.com/mwarcz/lazynpmplus
cd lazynpmplus
make build       # compiles ./lazynpmplus

For a standalone Docker build (no published image), see docker/standalone/.


Compatibility

lazynpmplus targets the Nginx Proxy Manager REST API v2.x. NPMplus is a fork that exposes the same API version, so the same range applies to both.

lazynpmplus Supported NPM API
0.x 2.122.15 (NPM); NPMplus latest

The tool's version is independent of NPM's. lazynpmplus uses its own SemVer and is not synced to the NPM version number — NPM and NPMplus release on different schemes, and the tool needs to version its own fixes and features separately. Compatibility is expressed by the range above, not by the version number.

The dashboard shows the detected server version; if it falls outside the tested range, a non-blocking warning is shown (the app keeps working).

NPM vs NPMplus — port 81 scheme

The two forks differ in how they expose the admin/API on port 81, which affects --server:

Admin/API on port 81 --server TLS verification
jc21 NPM plain HTTP http://host:81 default (insecure_tls: false)
NPMplus HTTPS, self-signed cert https://host:81 --insecure / insecure_tls: true

NPMplus ships a self-signed certificate by default, so without --insecure (LAZYNPMPLUS_INSECURE_TLS=true) the connection fails certificate verification. If you put NPMplus behind a trusted certificate, you can leave verification on.


Configuration

Settings are merged with the following precedence (highest wins):

  1. CLI flags (--server, --identity, --lang, …)
  2. Environment variables (LAZYNPMPLUS_*)
  3. Local ./.lazynpmplus.yml
  4. Global ~/.config/lazynpmplus/.lazynpmplus.yml

CLI flags

Flag Env Default Description
--server LAZYNPMPLUS_SERVER Base URL of NPM (e.g. http://127.0.0.1:81)
--identity LAZYNPMPLUS_IDENTITY Login email
--secret LAZYNPMPLUS_SECRET Password (prefer env or prompt)
--variant LAZYNPMPLUS_VARIANT auto Force token bearer: npm (JWT body), npmplus (session cookie), or auto (detect)
--insecure LAZYNPMPLUS_INSECURE_TLS false Skip TLS verification
--lang LAZYNPMPLUS_LANG auto-detect en or cs (or a code added via --locale-file)
--locale-file LAZYNPMPLUS_LOCALE_FILE Path to an external locale YAML; file name = language code (e.g. de.yml). Overrides a built-in language of the same code
--lang-strict LAZYNPMPLUS_LANG_STRICT false Disable the English fallback; missing keys render as the raw key (handy while translating)
--theme LAZYNPMPLUS_THEME Color theme (future use)
--config Path to a config YAML (replaces defaults)
--token-path ~/.config/lazynpmplus/token.json Token file path
--log-level LAZYNPMPLUS_LOG_LEVEL — (off) debug, info, warn or error; empty disables logging
--log-file LAZYNPMPLUS_LOG_FILE ~/.config/lazynpmplus/lazynpmplus.log Log file path
--log-format LAZYNPMPLUS_LOG_FORMAT text text or json

Config file (~/.config/lazynpmplus/.lazynpmplus.yml)

server: https://192.168.1.100:81   # NPMplus: HTTPS on 81 (jc21 NPM uses http://)
identity: admin@example.com
variant: npmplus
insecure_tls: true                 # NPMplus self-signed cert; false for jc21/trusted cert
language: cs
theme: default
log_level: warn       # off when empty
log_format: text      # text | json
# log_file: /var/log/lazynpmplus.log

Warning: setting secret: in a YAML config file stores your password as plaintext on disk. The application logs a warning when it detects this. Prefer supplying the password via the LAZYNPMPLUS_SECRET environment variable or the --secret flag (both avoid writing the value to a file), or simply type it on the login screen.

For a ready-to-mount example documenting every available option (with inline notes on what each does), see docker/compose/config-file/lazynpmplus.yml.

Tip: press e on the dashboard to export the current settings — the effective configuration (after merging flags, env and files) is written to the working directory as a YAML config file or a .env file. It doubles as a shortcut and as a way to audit what the app actually uses. The password is never written (only a commented placeholder).

Environment variables

Most config keys map to LAZYNPMPLUS_<UPPERCASED_KEY>. Mind the few exceptions: the language env var is LAZYNPMPLUS_LANG (YAML key language), TLS is LAZYNPMPLUS_INSECURE_TLS (YAML key insecure_tls), and --config / --token-path have no env equivalent — they are flags only. See the table above for the exact env name of each option.

export LAZYNPMPLUS_SERVER=http://192.168.1.100:81
export LAZYNPMPLUS_IDENTITY=admin@example.com
export LAZYNPMPLUS_LANG=cs

Token storage

The login token is saved in ~/.config/lazynpmplus/token.json (mode 0600). NPM stores a JWT; NPMplus stores a session cookie — token.json handles both. Tokens are stored per-server: switching --server between instances keeps each session alive independently without re-logging in. Passwords are never stored. The token is refreshed automatically on 401.

Logging

Logging is off by default and is enabled by setting a level (--log-level debug|info|warn|error). Records are structured (log/slog) and written to a file — by default ~/.config/lazynpmplus/lazynpmplus.log (mode 0600). Choose --log-format json for machine parsing.

The UI runs in the terminal alternate screen, so writing logs to stdout/stderr while the TUI is active corrupts the display. Prefer the log file. Secrets (password, token, session cookie) are never logged.

lazynpmplus --server http://127.0.0.1:81 --log-level debug
tail -f ~/.config/lazynpmplus/lazynpmplus.log

Usage

First run

# Authenticate and open the dashboard
./lazynpmplus --server http://127.0.0.1:81 --identity admin@example.com

Keyboard navigation

Key Action
/ Move selection
/ , Tab / Shift+Tab Switch tab (forms)
Enter Confirm / open detail
Esc Back / cancel
19 Open section (dashboard)
n Create new item
e Edit selected item
d Delete selected item
Space Enable / disable (host sections)
r Refresh
l Log out
? Help overlay
q / Ctrl+C Quit

Sections

# Section Read / Write
1 Proxy Hosts
2 Redirections
3 Dead Hosts
4 Streams
5 Access Lists
6 Certificates
7 Users read-only
8 Audit Log read-only
9 Settings read-only

Internationalisation

Supported languages

Language Code
English en
Czech cs

The list grows as locale files are added under internal/i18n/locales/.

Language resolution

The interface language is resolved in this order:

  1. --lang flag
  2. LAZYNPMPLUS_LANG environment variable
  3. language key in the config file
  4. Host locale ($LANG, $LC_MESSAGES, etc.)
  5. Fallback to English

Adding a built-in language: create a new file in internal/i18n/locales/ with the same keys as the reference en.yml. It is picked up automatically — no other code changes are needed.

Custom / external locale (no recompile)

You can load a translation from a file on disk, without rebuilding the binary — useful for trying out a new language or shipping your own wording when you don't agree with the bundled translation:

# Add a brand-new language (file name = language code):
lazynpmplus --locale-file ./de.yml --lang de

# Override the bundled Czech wording (file must be named cs.yml):
lazynpmplus --locale-file ./cs.yml --lang cs
  • The file name is the language code (de.ymlde, cs.ymlcs); name the file accordingly, then select it with --lang <code>.
  • An external file with the same code as a bundled language overrides it, so you can patch existing translations.
  • Use the reference internal/i18n/locales/en.yml as the list of keys to translate.

Spotting untranslated keys: by default a key missing from your file falls back to English. Add --lang-strict while translating to disable that fallback — missing keys then render as the raw key, so you can see exactly what's left to fill in.


Docker

The Quick start above covers the common paths. All examples live in docker/, with a README in every folder; docker/README.md is the full walkthrough — both deployment shapes (standalone vs compose), token persistence, and the maintainer notes for publishing images to GHCR + Docker Hub.


Related projects


License

MIT

About

A TUI client for Nginx Proxy Manager and its NPMplus fork. Manage proxy hosts, redirections, streams, access lists and certificates over the REST API - straight from an SSH terminal, no web UI required.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages