# Changelog All notable changes to the npm-api.sh script will be documented in this file. ## [3.6.9] - 2026-10-07 ### πŸ“ Documentation - **README: new "Wildcard certificate with Cloudflare (step by step)" guide**: prerequisites (Cloudflare zone, NPM user email used by Let's Encrypt since NPM 2.13), API token creation and `verify` check, generation, reuse of one wildcard certificate on many hosts (`--cert-show` / `--host-create` / `--host-ssl-enable HOST_ID CERT_ID`), permissions for other NPM users, troubleshooting table of the errors seen in v3.6.4 to v3.6.8. - **`--help` / `--examples`**: Cloudflare examples use `dns_cloudflare_api_token` (Global API Key shown as alternative), new "reuse an existing wildcard certificate" example, note that `--cert-email` is ignored by NPM >= 2.13, `--cert-email` dropped from wildcard examples. - **Wrong credential keys in examples fixed** (checked against NPM `dns-plugins.json`): OVH `dns_ovh_application_key` / `dns_ovh_application_secret` (was `dns_ovh_app_key` / `dns_ovh_app_secret`), Dynu `dns_dynu_auth_token` (was `dns_dynu_api_key`). ## [3.6.8] - 2026-10-07 ### πŸ”’ Security - **`--cert-generate` failure output** no longer prints the DNS provider credentials: `dns_provider_credentials` is masked in the "Request Data" debug line. ### πŸ› Fixes - **Cloudflare API tokens given as `dns_cloudflare_api_key`** (e.g. `cfut_...`) made certbot send them as a Global API Key ("Invalid format for X-Auth-Key header"). A value that is not a 37 hex chars Global API Key is now sent as `dns_cloudflare_api_token`, with a warning. The `--host-create` Cloudflare pre-check only runs for real Global API Keys. - Let's Encrypt log path in the troubleshooting hints: `/data/logs/letsencrypt.log` (was `/tmp/letsencrypt-log/...`), plus a DNS credentials hint for wildcard certificates. ## [3.6.7] - 2026-10-07 ### πŸ”Ž Compatibility - Audited every write call (tokens, users, proxy/redirection/dead/stream hosts, access lists, certificates) against the NPM v2.16.0 request schemas. NPM validates with type coercion but rejects unknown properties; the two issues below were the only mismatches left after v3.6.6. ### πŸ› Fixes - **`--access-list-update`**: the existing items/clients read from the API (with `id`, `hint`, `created_on`, `access_list_id`, ...) were sent back as-is and rejected with "must NOT have additional properties". They are now reduced to `{username, password}` (empty password keeps the current one) and `{address, directive}`. - **Certificate expiry**: the NPM API has no `expired` field, so `--cert-generate` never reused an existing valid certificate, `--cert-list`/`--cert-show` never showed "EXPIRED" and `--info`/stats always counted 0 expired. Expiry is now computed from `expires_on` (SQLite and ISO formats), `expired` is still used if present. ## [3.6.6] - 2026-10-07 ### πŸ› Fixes - **`--cert-generate` on NPM >= 2.13**: requests failed with "data/meta must NOT have additional properties" because NPM 2.13.0 removed `meta.letsencrypt_email` and `meta.letsencrypt_agree` (the email now comes from the NPM user account, TOS is always agreed). The script detects the NPM version and only sends these fields to NPM < 2.13. - **DNS challenge credentials**: NPM writes `dns_provider_credentials` as-is into the certbot INI file, so the JSON sent by the script could not be read by certbot. JSON objects passed to `--dns-credentials` are now converted to `key = value` lines; raw INI text is also accepted. ### πŸ“ Documentation - `--help` / README: `--cert-email` noted as NPM < 2.13 only, `--dns-credentials` accepts JSON or certbot INI text. ## [3.6.5] - 2026-10-07 ### πŸ› Fixes - **`--host-create ... --cert-generate "*.domain" --dns-provider ... --dns-credentials ...`**: the DNS options were ignored (the function read unset `DNS_PROVIDER`/`DNS_API_KEY`) and the provider/key were asked interactively; the wildcard test also looked at the host domain instead of the certificate domain. The `--dns-*` values are now used, the prompt only appears when they are missing (error with `-y`), and the Cloudflare pre-check reads `dns_cloudflare_api_key`/`dns_cloudflare_email` from the JSON (skipped for API tokens). - **`--host-create` with `--cert-generate`**: no longer runs a second certificate generation (with the host domain) when SSL activation fails; it now exits with an error. - **`--cert-generate --host-ssl-enable`**: failed with "No certificate ID available" when a valid certificate already existed, and with "No domain found in NPM" for wildcards. The existing certificate is now reused, the matching proxy host is looked up for every domain, and the error explains how to enable SSL manually. - `CERT_DNS_PROVIDER`/`CERT_DNS_CREDENTIALS` initialized globally (`set -u` safety). ### πŸ“ Documentation - **README**: wildcard host examples used `--host-create "*.example.com"`, which the script refuses; they now create `app.example.com` with a `*.example.com` certificate. ## [3.6.4] - 2026-10-07 ### πŸ› Fixes - **`--cert-generate`**: `--cert-email ` was documented in `--help` but rejected as "Unknown option"; the parser then stopped, so `--dns-provider`/`--dns-credentials` were ignored and wildcard DNS certificates failed with "Wildcard certificates require DNS challenge". The option is now parsed (positional email still works). ### πŸ“ Documentation - **`--cert-generate` help and examples**: `--cert-email` documented in `--help`, the option usage and error messages; DNS format fixed (`--dns-provider PROVIDER --dns-credentials 'JSON'` instead of the non-existent `dns-api-key`); wildcard examples now quote `"*.example.com"`; header example no longer shows a wildcard without DNS challenge. - **README**: same help/format fixes, missing `lws`/`tencentcloud-edgeone` providers added, `--cert-generate` usage no longer suggests positional DNS arguments. ## [3.6.3] - 2026-09-27 ### πŸ“ Documentation - **README**: removed all em dashes, dropped the token paragraph duplicated by the Description feature list. - **`--list` output**: example separator changed to ", e.g.". ## [3.6.2] - 2026-09-27 ### πŸ“ Documentation - **README Description rewritten** β€” concise intro plus a feature list (hosts, SSL, access, scriptability, tokens, backup, deps). - **README fixes** β€” typo `Ngins` β†’ `Nginx`; examples used non-existent `--update-host` (β†’ `--host-update`) and `--list-access` (β†’ `--access-list`); `--host-acl-enable 42,5` β†’ `--host-acl-enable 42 5` (two separate args); stale `Script Info: 3.0.0` in the `--info` sample output. ## [3.6.1] - 2026-09-24 ### πŸ”Ž Compatibility - Reviewed against **NPM v2.16.0**: no breaking API/data-model changes for the script. Token invalidation on password change is already handled transparently (`check_token()` live-tests the token via `GET /tokens` and regenerates it on any non-200 response). The new per-path access lists (Proxy Host modal) pass through unaffected via the existing `-l/--locations` raw-JSON flag. The `PermissionError` fix (403 instead of 404) does not affect the script's existing `404` "not found" checks. Certbot was updated upstream (may require DNS-plugin dependency tweaks server-side) β€” no code impact on the client script itself. ### πŸ“ Documentation - **`--cert-generate` help** β€” Added the two new Certbot DNS plugins introduced in NPM v2.16.0: `lws` (LWS) and `tencentcloud-edgeone` (Tencent Cloud EdgeOne). ## [3.6.0] - 2026-09-07 ### ✨ New Features - **`--json` global modifier** β€” Any read command (`--host-list`, `--host-show`, `--cert-list`, `--cert-show`, `--redirect-host-list`, `--stream-host-list`, `--dead-host-list`, `--access-list`, `--access-list-show`) now accepts a `--json` flag that outputs pure, unformatted JSON on stdout instead of the colored human tables β€” no decorative text, safe to pipe straight into `jq` or any monitoring/CI tool. Mutating commands (create/update/delete/enable/disable) and purely decorative ones (`--help`, `--info`, `--backup`, ...) are unaffected β€” this is opt-in and additive, the default (colored) output is unchanged. - Success returns valid JSON (array for lists, object for a single item) and exit 0. - A search with no match (e.g. `--cert-show` on an unknown domain) returns `[]` and exit 0 β€” not an error. - An unknown ID or an API error returns `{"error": "..."}` and exit 1. - `--json` can be placed before or after a command that takes no positional argument. For commands with an argument right after them (`--host-show `, `--cert-show `, ...), place `--json` before the command or after its argument, never in between. ### πŸ†• New Commands - **`--list`** β€” Lists every command compatible with `--json`, each with a ready-to-use example command (as a colored table, or as a JSON array of `{command, description, example}` objects when combined with `--json`). ### πŸ“ Documentation - `show_help()` and `README.md` β€” New `--json` / `--json --list` entries, corrected the misleading `--cert-show ... (JSON)` claim to `(add --json for raw JSON)`, and added a scripter-facing tip with usage examples near the top of the README. ## [3.5.0] - 2026-09-07 ### ✨ New Features - **Self-update check** β€” The script can now check GitHub for a newer release of itself. ### πŸ†• New Commands - **`--check-update`** β€” Queries the GitHub `releases/latest` API for this repo, compares the published release's `tag_name` to the script's own `VERSION`, and reports whether a newer version is available (with a link to the release). Requires a published GitHub Release on the newer tag to be detected β€” a bare `git tag` push is not enough. ### πŸ“ Documentation - `show_help()` and `README.md` β€” New `--check-update` entry and usage example. ## [3.4.2] - 2026-09-07 ### πŸ› Fixes - **`--backup-host`, `--backup-host-list`, `--restore-host` and `--restore-backup` crashed with "command not found"** β€” Their dispatch functions (`backup_host`, `list_backups`, `restore_host`, `restore_backup`) were called but never defined anywhere in the script. - `backup_host()` and `list_backups()` are now implemented: `--backup-host [id]` backs up one proxy host (or all if no id given), including its SSL certificate, using the same on-disk layout as `--backup`; `--backup-host-list` lists available per-host backups (domain, ID, last backup date) β€” purely local, no API call needed. - `--restore-host` and `--restore-backup` are **removed** rather than implemented: restoring proxy hosts (and especially SSL certificates) through the NPM API is not reliably possible, which is also why the pre-existing `restore_ssl_certificates` function was already dead code (gated behind a flag no CLI option ever set). Use `--backup-host`/`--backup` to keep exportable JSON snapshots, and recreate hosts through the NPM web UI if needed. ## [3.4.1] - 2026-09-07 ### πŸ› Fixes - **`display_dashboard()` now includes 404 Hosts and is grouped by category** β€” The dashboard shown by `./npm-api.sh` (no args) was missing 404 Hosts (Dead Hosts) entirely, and Redirection/Stream Hosts only showed a raw total with no Enabled/Disabled breakdown. The table is now grouped in the same order as the NPM web UI: Proxy Hosts β†’ Redirection Hosts β†’ Stream Hosts β†’ 404 Hosts (each with Enabled/Disabled counts) β†’ Access Lists β†’ Certificates β†’ Users. - **`full_backup()` now backs up Redirection Hosts, Stream Hosts and 404 Hosts** β€” These three host types (added in 3.4.0) were never included in `--backup`: no dedicated JSON files, no entry in `full_config*.json`, and no mention in the backup summary/file counts. A restore from a pre-3.4.1 backup would silently lose them. Each type now gets its own `.Redirection_Hosts/`, `.Stream_Hosts/` and `.Dead_Hosts/` directory (with a `_latest.json` symlink) and is merged into `full_config*.json` under `redirection_hosts`, `streams` and `dead_hosts`. - **`display_info()` backup statistics** β€” Same three host types now counted in the "Backup Statistics" block shown on script startup. - **NPM Version always showed "Unknown" in the dashboard** β€” `display_dashboard()` queried `${BASE_URL%/api}/version`, which returns the NPM web app's HTML shell, not JSON. It now queries `$BASE_URL/` (the API root, `{"version":{"major":...}}`) and parses it with `jq`. ### πŸ’… UI - **Startup output reordered** β€” The dashboard table now appears right after "Script Variables Information" and before the "Backup Statistics" section (previously it was printed last). The "Backup Statistics" section also got a titled header with an underline, matching the style already used for the dashboard title. The `πŸ’‘ Use --help...` hint now prints at the very end of the output, after "Backup Locations". ## [3.4.0] - 2026-09-07 ### ✨ New Features - **Full Stream Host management (TCP/UDP forwarding)** β€” Five new commands cover the complete lifecycle of a stream host: list, create/update, enable, disable, and delete. Requested in [discussion #32](https://github.com/Erreur32/nginx-proxy-manager-Bash-API/discussions/32) (e.g. forwarding port 53 TCP+UDP to a Pi-hole container). - **Full Dead Host (404 Host) management** β€” Same five-command lifecycle for NPM's "404 Hosts", discovered missing while auditing the [official NPM API schema](https://github.com/NginxProxyManager/nginx-proxy-manager/tree/develop/backend/schema) for the Stream Host work above. - **`cert_delete()` referencing-hosts check extended** β€” The warning shown before deleting/purging a certificate now also checks `/nginx/streams` and `/nginx/dead-hosts`, not just proxy/redirection hosts. ### πŸ†• New Commands - **`--stream-host-list`** β€” Display all Stream Hosts in a table (ID, incoming port, status, TCP/UDP, forward host:port). - **`--stream-host-create --forward-host --forward-port [options]`** β€” Create a stream host (POST) or silently update it if the incoming port already exists (PUT). Options: `--tcp`, `--udp`, `--cert-id `, `-y`. - **`--stream-host-delete [-y]`** β€” Delete with interactive confirmation (skippable with `-y`). - **`--stream-host-enable `** β€” Enable via NPM's native endpoint `POST /streams/{id}/enable`. - **`--stream-host-disable `** β€” Disable via `POST /streams/{id}/disable`. - **`--dead-host-list`** β€” Display all Dead Hosts (404) in a table (ID, domain, status, SSL/certificate). - **`--dead-host-create [options]`** β€” Create a dead host (POST) or silently update it if the domain already exists (PUT). Options: `--cert-id `, `--ssl-forced true|false`, `--http2 true|false`, `--hsts true|false`, `--hsts-subdomains true|false`, `-a/--advanced-config`, `-y`. - **`--dead-host-delete [-y]`** β€” Delete with interactive confirmation (skippable with `-y`). - **`--dead-host-enable `** β€” Enable via NPM's native endpoint `POST /dead-hosts/{id}/enable`. - **`--dead-host-disable `** β€” Disable via `POST /dead-hosts/{id}/disable`. ### πŸ“ Documentation - `show_help()` β€” New _Stream Host Management_ and _Dead Host (404) Management_ sections. - `examples_cli()` β€” New Stream Hosts and Dead Hosts (404) example subsections, including the Pi-hole DNS forwarding use case from discussion #32. - `README.md` β€” Options and Examples sections updated to match. ### πŸ”Ž Compatibility - Reviewed against the official NPM `develop` branch schema (`backend/schema/paths/nginx/{streams,dead-hosts}/`): field names, requiredness and endpoints confirmed unchanged, no breaking changes for the script. ## [3.3.0] - 2026-06-01 ### ✨ New Features - **`--cert-delete --purge`** β€” New optional `--purge` flag. After the API soft-delete (NPM sets `is_deleted=1`, which only removes the cert from the list/UI), `--purge` also deletes the leftover on-disk files: `custom_ssl/npm-`, `letsencrypt/live|archive/npm-` and `letsencrypt/renewal/npm-.conf`. Requires `NGINX_PATH_DOCKER` to be set in `npm-api.conf`; without it (or if the path is not accessible) `--purge` is a safe no-op with a clear message. The DB row is intentionally left untouched to avoid referential-integrity risk and DB-schema drift between NPM versions. - **`--user-create … --admin`** β€” New optional `--admin` flag. Users are now created as **standard (non-admin)** by default; pass `--admin` to grant the admin role. Previously every created user was forced to `roles: ["admin"]`. - **`--cert-show-all`** β€” Now works as an alias of `--cert-list` (it was shown in usage text but had no parser case). ### πŸ’… Output / Display - **`host_list()` β€” long & multiple domains** β€” Proxy hosts with several domains (or a very long one) no longer break column alignment. The first domain stays on the main row; the remaining domains are listed below, indented under the DOMAIN column. New `truncate_pad()` helper truncates over-long values with an ellipsis (`…`) instead of overflowing, applied to the DOMAIN and TARGET columns. - **`redirect_host_list()` β€” same alignment fix** β€” Applied the identical treatment to the Redirection Hosts table (it had the same `pad`-without-truncation overflow bug): `truncate_pad()` on the DOMAIN and FORWARD DOMAIN columns, plus multi-line display for hosts with multiple domains. - **`show_help()` β€” aligned description column** β€” New `help_row()` helper measures visible width (ignoring ANSI color codes and counting wide emoji such as πŸ†” as 2 cells) and aligns every description to a fixed column. Lines whose left part is wider than the column (e.g. `--cert-download`) wrap their description onto the next line, still aligned. All option lines converted to `help_row`. ### πŸ› Bug Fixes - **`list_cert_all()` β€” wrong Valid/Expired statistics** β€” The stats used `select(.expires_on > now)`, comparing an ISO date _string_ to the numeric `now`; in jq every string sorts greater than every number, so "Valid" always equalled the total and "Expired" was always 0. Now uses the API's own `.expired` boolean (`select(.expired == true)` / `!= true`). - **`cert_delete()` β€” no check that the certificate is still in use** β€” Before deleting, the script now lists the proxy/redirection hosts that still reference the certificate and warns that they will be left with a dangling `certificate_id`. When combined with `--purge`, the purge is now _refused_ while the cert is still referenced (its on-disk files are in use), to avoid breaking live TLS. - **`--access-list-create` β€” command ran during argument parsing; bottom dispatch was dead code** β€” `ACCESS_LIST_CREATE` was never set, so the dispatcher branch was unreachable and the function executed mid-parse. Now aligned with `--access-list-update`: arguments are stashed (`ACCESS_LIST_CREATE_ARGS`) and the function runs from the dispatch block. - **`--access-list-create --pass-auth` β€” asymmetric parsing** β€” The create parser set `--pass-auth` with no value while `--access-list-update` (and the documented usage `--pass-auth true`) expects a `true|false` argument, so `--pass-auth true` failed with "Unknown option true". Create now consumes and validates the value like update. - **`host_acl_enable` / `host_acl_disable` β€” error handling** β€” Read the error from the wrong jq path (`.message` instead of `.error.message`) and never checked the HTTP status. Now capture `HTTPSTATUS`, treat non-200 as failure (`exit 1`), and read `.error.message`. - **`host_show()` β€” wrong fields** β€” Read `.websockets_enabled` (always null) instead of the real field `.allow_websocket_upgrade`, and passed `.forward_scheme` (`http`/`https`) through `colorize_boolean` (mislabelled). Both fixed. - **`user_create` β€” no longer writes the raw API response to `/tmp/npm_debug.log`** (a world-readable path). - **`cert_delete` β€” declining the confirmation now exits 0** (deliberate user choice) instead of 1. - **Exit codes** β€” `host_enable` / `host_disable` and `redirect_host_enable` / `redirect_host_disable` now `return 1` on every failure path (previously they printed the error but still returned success). - **`full_backup` β€” `success_count` double-counted** β€” Each backed-up certificate incremented the success counter twice, inflating the final summary. Fixed to count once. ### πŸ›‘οΈ Robustness - **`--info` dispatch** β€” Added a dedicated `elif [ "$INFO" = true ]` branch so `--info` works even when combined with other flags (it previously only ran as the no-argument fallback). - **`set -u` safety** β€” Initialized `CERT_ID`, `GENERATED_CERT_ID`, `USER_ID` and `search_term` in the top variable block (they were referenced in the dispatcher before being set on some code paths). - **`set -e` safety** β€” Guarded the 11 `[ "$HTTP_STATUS" -eq … ]` checks with `${VAR:-0}` so an empty/garbled response falls into the error branch instead of aborting the script, and converted the 10 `((var++))` counters to `var=$((var + 1))` (the `((x++))` form returns exit status 1 when `x` is 0, which aborts under `set -e`). - **Consistent boolean defaults** β€” `HTTP2_SUPPORT`, `SSL_FORCED`, `HSTS_ENABLED` and `HSTS_SUBDOMAINS` now default to `false` instead of `0` (same class as the Issue #23 fix), and the duplicate `AUTO_YES=false` declaration was removed. ### ⚑ Performance - **Token read once per run** β€” The API token was re-read from disk with `$(cat "$TOKEN_FILE")` on every single request (~81 call sites). It is now cached in a global `$TOKEN` (populated by `check_token_notverbose`); headers use `${TOKEN:-$(cat "$TOKEN_FILE")}` so an empty cache still falls back safely to reading the file. - **`host_list` β€” one certificate fetch instead of one per host** β€” The CERT DOMAIN column previously triggered a `GET /nginx/certificates/` call for every proxy host that had SSL. The full certificate list is now fetched once and resolved locally through an `id β†’ domains` map, turning N API round-trips into 1. ### ♻️ Code Quality / Cleanup - **Factored the duplicated certificate formatter** β€” The three near-identical `jq` cert-formatting one-liners (in `cert_show` ID/domain branches and `list_cert_all`) now share a single `CERT_JQ_FMT` format string and a `cert_colorize` helper; this also fixes the inconsistent `Provider :` vs `Provider:` label. - **`access_list` table** β€” Guarded `proxy_host_count` against `null` (`// 0`), truncated long names to the column width via `truncate_pad`, and made the "Proxy Hosts" cell fixed-width so a 2-digit count no longer breaks the box border. - **Consistent confirmation prompts** β€” All `(y/n)` prompts now accept `^[Yy]$` (the two French leftovers accepting `O/o` were aligned). - **English usage text** β€” Translated the remaining French usage/error strings (`--host-update`, `--access-list-show`) to match the rest of the CLI. - **Removed dead code** β€” Dropped the unimplemented `-O` / `-J` flag stubs (they only printed `todo`) and a duplicated `GET /nginx/certificates` block in `cert_generate`. ### πŸ†• Documentation / Help - **`--host-list-full`** β€” Now shown in `--help` (was a functional but hidden/commented command). Lists all proxy hosts with full details (JSON). - **`--cert-generate`** β€” Help now lists the new NPM v2.15.0 Certbot DNS plugins: `hostinger`, `rcodezero`, `hoster.by`. - Minor help wording fixes: `Show Default…` (double space) and `Check Check current token info` (duplicated word) cleaned up. ### πŸ”Ž Compatibility - Reviewed against **NPM v2.15.0**: no proxy-host/certificate data-model changes, version is read dynamically, and DNS provider names are passed through to the API β€” so no breaking changes for the script. ## [3.2.0] - 2026-03-31 ### ✨ New Features - **Full Redirection Host management** β€” Five new commands cover the complete lifecycle of a redirect host: list, create/update, enable, disable, and delete. - **Configurable HTTP redirect codes** β€” Choose from 301, 302, 303, 307, or 308 (default: 301). - **preserve-path option** β€” Optionally preserve the URI path on redirect (`--preserve-path true`). ### πŸ†• New Commands - **`--redirect-host-list`** β€” Display all Redirection Hosts in a table (ID, domain, status, HTTP code, SSL, forward domain). - **`--redirect-host-create --forward-domain [options]`** β€” Create a redirect host (POST) or silently update it if the domain already exists (PUT). Options: `--forward-scheme http|https`, `--http-code 301|302|303|307|308`, `--preserve-path true|false`, `-b/--block-exploits`, `-a/--advanced-config`, `-y`. - **`--redirect-host-delete [-y]`** β€” Delete with interactive confirmation (skippable with `-y`). - **`--redirect-host-enable `** β€” Enable via NPM's native endpoint `POST /redirection-hosts/{id}/enable`. - **`--redirect-host-disable `** β€” Disable via `POST /redirection-hosts/{id}/disable`. ### πŸ› Bug Fixes - **`check_nginx_access()`** β€” Undefined variable `$API_PORT` replaced with `$NGINX_PORT`. - **`host_search()`** β€” Error message incorrectly referenced `--host-enable` instead of `--host-search`. - **Dead code** β€” Two `echo "DEBUG: ..."` statements left in production in the `--host-create` block removed. ### πŸ“ Documentation - `show_help()` β€” New _Redirection Host Management_ section. - `examples_cli()` β€” New 301/302 redirect examples with and without `--preserve-path`. - `README.md` β€” Options and Examples sections updated; backup/restore limitation clearly documented. - `.gitignore` β€” Added `docs/`, `npm-api.conf`, `data/`, `.idea/`, `*.log`. ## [3.1.0] - 2025-01-27 ### πŸ› Bug Fixes - **`host_list` fails when proxy hosts have multiple domain names** ([PR #28](https://github.com/Erreur32/nginx-proxy-manager-Bash-API/pull/28)) - **The problem**: When a proxy host had multiple domain names (e.g., "domain1.com, domain2.com"), the `host_list()` function would fail to parse the output correctly because it used space-separated values with `read`, which broke when domain names contained spaces or commas. - **Why it broke**: The original implementation used `join(", ")` to combine multiple domain names, then tried to parse with `read -r id domain enabled certificate_id`, which failed when the domain string contained spaces or multiple domains. - **What we did**: - Changed the delimiter from spaces to tabulation (`\t`) for safe parsing - Updated the `jq` command to use tab-separated values: `"\(.id)\t\(.domain_names | join(", "))\t..."` - Modified the `read` command to use `IFS=$'\t'` to properly handle tab-separated input - **Technical details**: - Tab delimiter (`\t`) is safer than spaces because domain names can contain spaces - Using `IFS=$'\t'` ensures proper field separation - This fix ensures that proxy hosts with multiple domain names are displayed correctly - **Examples**: ```bash # Now works correctly with multiple domains! πŸŽ‰ ./npm-api.sh --host-list # Displays: "domain1.com, domain2.com" correctly in the DOMAIN column ``` ### ✨ New Features - **Added TARGET column to `host_list` output** ([PR #29](https://github.com/Erreur32/nginx-proxy-manager-Bash-API/pull/29)) - **Feature**: The `host_list` command now displays a TARGET column showing where each proxy host forwards traffic - **What it shows**: The TARGET column displays the forwarding configuration in the format `scheme://host:port` (e.g., `http://192.168.1.10:8080`) - **Why it's useful**: This allows users to quickly see the destination of each proxy host without needing to run `--host-show` for each host - **Technical details**: - Extracts `forward_scheme`, `forward_host`, and `forward_port` from the API response - Formats the target as `${forward_scheme:-http}://${forward_host}:${forward_port}` - Displays "N/A" if forwarding information is not available - The column is positioned between SSL and CERT DOMAIN columns for better readability - **Examples**: ```bash # Now shows TARGET column with forwarding information ./npm-api.sh --host-list # Output includes: ID | DOMAIN | STATUS | SSL | TARGET | CERT DOMAIN # TARGET shows: http://192.168.1.10:8080 ``` ### πŸ”§ Technical Improvements - **Improved `host_list` function robustness**: Combined the fixes from PR #28 and PR #29 to create a more robust and informative listing function - **Better column formatting**: Adjusted column widths to accommodate the new TARGET column while maintaining readability ## [3.0.7] - 2025-01-27 ### πŸ› Bug Fixes - **IP whitelist not showing in `--access-list-show` command** ([Issue #26](https://github.com/Erreur32/nginx-proxy-manager-Bash-API/issues/26)) - **The problem**: When you ran `./npm-api.sh --access-list-show 5`, it showed "No IPs whitelisted" even though IPs were actually configured. Classic! πŸ˜… - **Why it broke**: NPM's API changed (thanks evolving schemas...) and now you need to pass the `expand=items,clients` parameter to get all the details. Without it, the API just returns basic info without items and clients. - **What we did**: - Added `?expand=items%2Cclients` to API calls in `access_list_show()` and `access_list_update()` - Improved the backup function to fetch each access list individually with the expand parameter (so we get a complete backup with all details) - **Technical details** (for the curious): - URL encoding: `items%2Cclients` = `items,clients` URL-encoded - Modified GET requests in `access_list_show()` and `access_list_update()` - Backup now fetches each access list one by one with expand to make sure we get everything - **Examples**: ```bash # Now it works correctly! πŸŽ‰ ./npm-api.sh --access-list-show 5 # Update also retrieves complete data ./npm-api.sh --access-list-update 5 --name "new_name" ``` - **"Unbound variable" error when you forget the ID** - **The problem**: If you ran `./npm-api.sh --access-list-show` without an ID, it crashed with a nice "unbound variable" error (thanks `set -eu` doing its job a bit too well πŸ˜„) - **Why it broke**: We were directly assigning `$1` to a variable without checking if it existed. With `set -eu`, bash doesn't like that at all! - **What we did**: - Added a check before assigning the variable (we check if `$# -eq 0` or if `$1` starts with `-`) - Added a friendly error message with examples and tips - Aligned with other commands (`--access-list-update`, `--access-list-delete`) for consistency - **Technical details**: - Added check: `if [ $# -eq 0 ] || [[ "$1" == -* ]]` before assignment - Exit with code 1 to prevent the script from continuing - **Examples**: ```bash # Now it shows a helpful message instead of crashing ./npm-api.sh --access-list-show # Correct usage ./npm-api.sh --access-list-show 5 ``` ### πŸ”§ Technical Improvements - **API schema alignment**: Updated all access list API calls to be compatible with NPM's new schema requirements - **Enhanced backup**: Backup now fetches each access list individually with expand, so we're sure to have all details (items and clients) in the backup - **Better error handling**: Added validations and clearer error messages when arguments are missing ### πŸ“ Documentation - More descriptive and helpful error messages - Added examples in error messages to guide users - Improved consistency in error handling across all access-list commands ## [3.0.6] - 2025-01-20 ### πŸ†• New Features - **Added certificate download functionality with fallback support** ([PR #20](https://github.com/Erreur32/nginx-proxy-manager-Bash-API/pull/20)) - **Issue**: Certificate download failed on newer NPM installations due to API changes - **Solution**: - Added `--cert-download` command to download certificates as ZIP files - Implemented automatic fallback from new API (JSON) to legacy API (ZIP) - Added support for wildcard file matching (cert*.pem, privkey*.pem, etc.) - Created standardized output format with .crt, .key, .chain.crt files - **Technical Details**: - New API: Uses `/nginx/certificates/{id}/certificates` endpoint with JSON response - Legacy API: Uses `/nginx/certificates/{id}/download` endpoint with ZIP response - Automatic detection of certificate files with wildcards (supports cert8.pem, cert9.pem, etc.) - Creates both individual files and ZIP archive for easy distribution - Proper error handling and cleanup of temporary files - **Usage Examples**: ```bash # Download certificate with default settings ./npm-api.sh --cert-download 123 # Download to specific directory ./npm-api.sh --cert-download 123 ./certs # Download with custom name ./npm-api.sh --cert-download 123 ./certs mydomain ``` - **Output Files**: - `{cert_name}.crt` - Certificate file - `{cert_name}.key` - Private key file - `{cert_name}.chain.crt` - Intermediate certificate (if available) - `{cert_name}.fullchain.crt` - Full chain certificate (if available) - `{cert_name}_metadata.json` - Certificate metadata - `{cert_name}_certificate.zip` - ZIP archive containing all files ## [3.0.5] - 2025-01-20 ### πŸ› Bug Fixes - **Fixed `-l` and `-a` options being ignored in host creation** ([Issue #22](https://github.com/Erreur32/nginx-proxy-manager-Bash-API/issues/22)) - **Issue**: The commands `./npm-api.sh --host-create example.com -i 192.168.1.10 -p 8080 -a 'proxy_set_header X-Real-IP $remote_addr;'` and `./npm-api.sh --host-create example.com -i 192.168.1.10 -p 8080 -l '[{"path":"/api","forward_host":"192.168.1.11","forward_port":8081}]'` were showing "Unknown option ignored" warnings - **Root Cause**: The options `-l` (custom_locations) and `-a` (advanced_config) were documented in help text but not implemented in the argument parsing for `--host-create` - **Solution**: - Added support for `-l|--custom-locations` option in argument parsing - Added support for `-a|--advanced-config` option in argument parsing - Updated help messages to include these options in the optional parameters list - Added proper error handling and validation for both options - **Technical Details**: - Added `-l|--custom-locations` case in argument parsing with JSON validation - Added `-a|--advanced-config` case in argument parsing with string validation - Updated all help message sections to include the new options - Added example usage in error messages for better user guidance - **Usage Examples**: ```bash # Create host with custom locations ./npm-api.sh --host-create example.com -i 192.168.1.10 -p 8080 -l '[{"path":"/api","forward_host":"192.168.1.11","forward_port":8081}]' # Create host with advanced configuration ./npm-api.sh --host-create example.com -i 192.168.1.10 -p 8080 -a 'proxy_set_header X-Real-IP $remote_addr;' # Create host with both custom locations and advanced config ./npm-api.sh --host-create example.com -i 192.168.1.10 -p 8080 -l '[{"path":"/api","forward_host":"192.168.1.11","forward_port":8081}]' -a 'proxy_set_header X-Real-IP $remote_addr;' ``` - **Fixed `--websocket` and `--cache` options not being respected in host creation** ([Issue #23](https://github.com/Erreur32/nginx-proxy-manager-Bash-API/issues/23)) - **Issue**: The commands `./npm-api.sh --host-create example.com -i 192.168.1.100 -p 8081 --cache true --websocket true` were not enabling caching and websocket support in NPM - **Root Cause**: - Variable naming mismatch in argument parsing (`CACHE_ENABLED` vs `CACHING_ENABLED`, `WEBSOCKET_SUPPORT` vs `ALLOW_WEBSOCKET_UPGRADE`) - Incorrect default value for `ALLOW_WEBSOCKET_UPGRADE` (was `1` instead of `false`) - **Solution**: - Fixed variable names in argument parsing to match the variables used in the JSON payload - Corrected default value for `ALLOW_WEBSOCKET_UPGRADE` to `false` - Updated function call to use correct variable names - **Technical Details**: - Changed `cache) CACHE_ENABLED="$2"` to `cache) CACHING_ENABLED="$2"` - Changed `websocket) WEBSOCKET_SUPPORT="$2"` to `websocket) ALLOW_WEBSOCKET_UPGRADE="$2"` - Updated function call parameters to use correct variable names - Fixed default value: `ALLOW_WEBSOCKET_UPGRADE=1` β†’ `ALLOW_WEBSOCKET_UPGRADE=false` - **Usage Examples**: ```bash # Create host with caching enabled ./npm-api.sh --host-create example.com -i 192.168.1.100 -p 8081 --cache true # Create host with websocket support enabled ./npm-api.sh --host-create example.com -i 192.168.1.100 -p 8081 --websocket true # Create host with both caching and websocket support ./npm-api.sh --host-create example.com -i 192.168.1.100 -p 8081 --cache true --websocket true ``` - **Fixed `--allow` and `--deny` options not working in access-list commands** ([Issue #24](https://github.com/Erreur32/nginx-proxy-manager-Bash-API/issues/24)) - **Issue**: The commands `./npm-api.sh --access-list-create "test" --allow "172.0.0.0/8"` and `./npm-api.sh --access-list-update 6 --allow "172.0.0.0/8"` were failing with "Unknown option --allow" error - **Root Cause**: The `--allow` and `--deny` options were documented in help text but not implemented in the actual functions - **Solution**: - Added full support for `--allow` and `--deny` options in `access_list_create()` function - Added full support for `--allow`, `--deny`, and `--users` options in `access_list_update()` function - Implemented comma-separated value parsing for multiple IPs/users - Added proper error handling and validation for all new options - **Technical Details**: - Added `--allow` option processing with comma-separated IP support - Added `--deny` option processing with comma-separated IP support - Added `--users` option processing with password prompts for each user - Updated help messages to include all available options - Maintained backward compatibility with existing `--access allow|deny ` syntax - **Usage Examples**: ```bash # Create access list with allow rules ./npm-api.sh --access-list-create "office" --allow "192.168.1.0/24,10.0.0.0/8" # Create access list with deny rules ./npm-api.sh --access-list-create "secure" --deny "192.168.1.100,10.0.0.50" # Update access list with new allow rules ./npm-api.sh --access-list-update 6 --allow "172.0.0.0/8" # Create access list with users and IP rules ./npm-api.sh --access-list-create "full_config" --users "admin1,admin2" --allow "10.0.0.0/8" --deny "10.0.0.50" ``` - **Fixed `--access-list-update` command not working with arguments** - **Issue**: The command `./npm-api.sh --access-list-update 123 --name "new_name"` was failing with "Unknown option: 123" error - **Root Cause**: The argument parsing for `--access-list-update` was not properly capturing the access list ID and subsequent arguments - **Solution**: - Fixed argument parsing to properly capture the access list ID - Implemented proper argument storage and passing to the function - Corrected JSON payload structure to match API schema expectations - **Technical Details**: - Changed from interactive `read` prompts to command-line argument processing - Updated payload structure to use `satisfy_any` (boolean) instead of `satisfy` (string) - Removed unsupported fields (`auth_type`, `whitelist`) from API payload - Added support for `--name`, `--satisfy`, and `--pass-auth` options - **Usage Examples**: ```bash # Update access list name ./npm-api.sh --access-list-update 4 --name "new_name" # Update satisfaction mode ./npm-api.sh --access-list-update 4 --satisfy any # Update multiple properties ./npm-api.sh --access-list-update 4 --name "test_script" --satisfy any ``` ### πŸ”§ Technical Improvements - **Enhanced Argument Processing**: Improved command-line argument parsing for access list operations - **API Schema Compliance**: Updated JSON payload structure to match official NPM API schema - **Error Handling**: Better error messages and validation for access list operations - **Code Consistency**: Aligned `access_list_update` function structure with `access_list_create` ### πŸ“ Documentation Updates - Updated help messages and examples for `--access-list-update` command - Added proper usage examples in error messages - Improved command-line argument validation feedback ## [3.0.0] - 2025-03-24 ### πŸ”„ Breaking Changes - **Host Creation Command Simplified** ```diff - OLD: ./npm-api.sh -d example.com -i 192.168.1.10 -p 8080 + NEW: ./npm-api.sh --host-create example.com -i 192.168.1.10 -p 8080 ``` The `-d` option has been removed in favor of a more intuitive positional argument after `--host-create` ### New Commands (2.8.0) - `--access-list`: List all available access lists - `--access-list-show `: Show detailed information for a specific access list - `--access-list-create`: Create a new access list - `--access-list-update`: Update an existing access list - `--access-list-delete`: Delete an access list - `--list-cert`: List certificates filtered by domain name - `--list-cert-all`: List all SSL certificates ### New Long Options Format - Certificate Generation: ```diff - OLD: ./npm-api.sh --cert-generate example.com admin@example.com + NEW: ./npm-api.sh --cert-generate example.com --cert-email admin@example.com ``` - Wildcard Certificate with DNS Challenge: ```diff - OLD: ./npm-api.sh --cert-generate "*.example.com" admin@example.com --dns-provider cloudflare --dns-credentials '{"dns_cloudflare_email":"your@email.com","dns_cloudflare_api_key":"your_api_key"}' + NEW: ./npm-api.sh --cert-generate "*.example.com" \ + --cert-email admin@example.com \ + --dns-provider cloudflare \ + --dns-credentials '{"dns_cloudflare_email":"your@email.com","dns_cloudflare_api_key":"your_api_key"}' ``` ### Renamed Commands - `--list-ssl-cert` β†’ `--list-cert` - `--create-user` β†’ `--user-create` - `--delete-user` β†’ `--user-delete` - `--list-users` β†’ `--user-list` - `--list-access` β†’ `--access-list` - `--update-host` β†’ `--host-update` ### Enhanced Commands - `--generate-cert`: Added support for wildcard certificates and DNS challenges - Add Wildcard support. - Support for multiple DNS providers (Dynu, Cloudflare, DigitalOcean, etc.) ### Syntax Changes - Host-related commands now consistently use the `--host-` prefix - User-related commands now consistently use the `--user-` prefix - Certificate-related commands now consistently use the `--cert-` prefix ### ✨ New Features - **Smart certificate management in SSL configuration**: - Automatic detection of existing certificates for domains - Automatic selection of single existing certificates - Selection system for multiple certificates: - Auto-selects most recent with `-y` flag - Interactive selection without `-y` flag - Integration with certificate generation workflow - Enhanced SSL status display with detailed configuration state - Improved error handling and debug information - Configurable SSL parameters: - SSL Forced - HTTP/2 Support - HSTS - HSTS Subdomains - **Enhanced Host Creation** - Simplified command syntax with positional domain argument - Improved parameter validation - Better error messages with clear examples - Default values for optional parameters - **Improved Error Handling** - Clear error messages for missing parameters - Validation of domain name format - Parameter type checking (e.g., port numbers, boolean values) - Helpful usage examples in error messages - Added comprehensive dashboard with `display_dashboard()` showing: - Proxy hosts status (enabled/disabled) - SSL certificates (valid/expired) - Access lists and clients - System statistics - Enhanced SSL Certificate Management: - Improved wildcard certificate support - Enhanced domain validation - DNS challenge management for wildcard certificates - Support for multiple DNS providers (Cloudflare, DigitalOcean, etc.) - **Enhanced Access List Management**: - Detailed view for individual access lists - Colored output for better readability - Display of users and IP counts - Clear visualization of allow/deny rules - Authentication status indicators - Satisfaction mode display (Any/All) - Proxy host count integration - Improved formatting and layout - Better error handling for null values - Comprehensive legend for status indicators ### πŸ› οΈ Code Optimizations - Removed redundant parameter validations - Streamlined host creation logic - Unified error message format - Better code organization - Enhanced Token Management: - Automatic validation - Smart renewal - Secure storage - Improved Host Management Commands: - Enhanced display with `host_show()` - Better error handling - Advanced configuration support - Improved access list display with: - Dynamic column sizing - Proper null value handling - Efficient data processing - Better color management - Enhanced table formatting ### πŸ“š Documentation - Updated access list command documentation: - Added examples for detailed view - Improved command descriptions - Better parameter explanations ### πŸ” Security - Enhanced input validation - Better parameter sanitization - Improved error handling for invalid inputs ### πŸ› οΈ Fixes and Optimizations - Fixed SSL certificate management bugs - Improved user input validation - Optimized API requests - Enhanced HTTP error handling ### πŸ™ Remerciements Thanks to [zafar-2020](https://github.com/zafar-2020) for the testing and helpful issue reports during the development of this release! ## [2.7.0] - 2025-03-08 ### Added - DNS Challenge Support - Added support for multiple DNS providers (Dynu, Cloudflare, DigitalOcean, etc.) - Implemented automatic DNS challenge detection for wildcard certificates - Added validation for DNS provider and API key parameters - Wildcard Certificate Support - Added ability to generate wildcard certificates (\*.domain.com) - Automatic detection of wildcard certificate requirements - Enforced DNS challenge requirement for wildcard certificates - Certificate Management Enhancements - Added ability to specify existing certificate by ID when enabling SSL - Implemented automatic certificate matching for domains - Added support for using wildcard certificates with host SSL configuration - Enhanced certificate search to match wildcard patterns ### Changed - Command Structure - Modified --generate-cert command to accept DNS parameters after email: ```bash --generate-cert domain [email] [dns-provider provider dns-api-key key] ``` - Updated --host-ssl-enable to accept optional certificate ID: ```bash --host-ssl-enable ID [cert_id] ``` - Help Documentation - Updated help section with detailed DNS challenge information - Added examples for wildcard certificates and different DNS providers - Improved documentation for SSL certificate management - Added clarification for supported DNS providers ### Improved - Error Handling - Added validation for DNS challenge parameters - Enhanced error messages for certificate operations - Improved feedback for wildcard certificate requirements - User Experience - Added automatic certificate selection when enabling SSL - Improved certificate matching logic - Enhanced feedback during certificate operations - Added clear examples for all new features ## [1.0.0] - Initial Release - Basic SSL certificate management - Proxy host configuration - User list