ollama-solaria-cutover, node-onboarding-tool (ze scripts/onboard/README.md), ha-diag-agent-deploy, npm-api (ze scripts/npm/README.md), node-onboarding (public). UWAGA: scripts/onboard/README.md jest linkowany z CLAUDE.md — odwolanie naprawiane w grupie 7. git mv + frontmatter, tresc nietknieta. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
5.8 KiB
| okf | type | visibility | status | updated | links |
|---|---|---|---|---|---|
| 0.1 | runbook | private | active | 2026-08-03 |
npm_api.py — sterowanie Nginx Proxy Manager przez REST API
CLI do zarzadzania dwoma instancjami NPM (PIHA, VPS) bez klikania w web UI.
Uzywa tego samego REST API co panel admina (/api/tokens, /api/nginx/*).
Dlaczego stdlib (urllib), nie requests
Skrypt uzywa wylacznie biblioteki standardowej Pythona (3.11+) — zero zaleznosci
do zainstalowania. To narzedzie CLI uruchamiane doraznie z roznych miejsc (SATURN,
laptop operatora), nie serwis z wlasnym obrazem Docker — pip install przed kazdym
uzyciem byloby tarciem bez korzysci. Zapotrzebowanie na API jest proste (JWT bearer,
JSON), wiec urllib.request w zupelnosci wystarcza.
Konfiguracja
cp scripts/npm/env.example scripts/npm/.env
# wypelnij NPM_PIHA_USER/PASS i NPM_VPS_USER/PASS realnymi danymi
.env jest gitignored (wzorzec *.env w .gitignore) — nigdy nie trafia do repo.
Adresy domyslne (nadpisywalne w .env przez NPM_PIHA_URL/NPM_VPS_URL):
| Instancja | URL | Uwaga |
|---|---|---|
piha |
http://192.168.31.5:81 |
LAN |
vps |
http://100.95.58.48:81 |
Tailscale mesh, NIE publiczny IP 135.181.153.108:81 |
Uzycie
python3 scripts/npm/npm_api.py --npm piha|vps <komenda> [opcje]
Komendy
token— loguje sie i pokazuje status + czas wygasniecia tokenu (test poswiadczen).list-hosts— tabela proxy hostow (id, domeny, forward, cert, ssl_forced, enabled).list-certs— tabela certyfikatow (id, provider, nice_name, domeny, expires_on).set-cert HOST_ID CERT_ID [--apply]— podpina certyfikat pod host. Dry-run domyslnie, realna zmiana tylko z--apply. NPM przeladowuje nginx sam po PUT. Rownowaznie:set-cert --host-id 14 --cert-id 38. Opcjonalne--ssl-forced/--no-ssl-forcedustawia przy okazji wymuszanie HTTPS.create-cert --domain ... [--timeout N] [--apply]— zamawia certyfikat Let's Encrypt (challenge HTTP-01). Dry-run domyslnie, realne zamowienie tylko z--apply.create-host --domain ... --forward-host ... --forward-port ... [opcje] [--apply]— tworzy nowy proxy host. Dry-run domyslnie, realna zmiana tylko z--apply.
create-cert — schemat payloadu (NPM 2.14.0)
Wbrew starszym poradnikom meta nie przyjmuje letsencrypt_email ani
letsencrypt_agree — schemat ma additionalProperties: false, wiec takie pola daja
400 data/meta must NOT have additional properties. Zweryfikowane w GET /api/schema
oraz w zrodle kontenera (/app/internal/certificate.js). Faktyczny payload to:
{"provider": "letsencrypt", "domain_names": ["example.com"], "meta": {"dns_challenge": false}}
Certbot dostaje --agree-tos na sztywno, a -m <email> bierze z konta uzytkownika NPM
(GET /api/users -> email). Jesli konto nie ma emaila, NPM zwraca
A valid email address must be set on your user account to use Let's Encrypt.
POST /nginx/certificates jest synchroniczne — w jednym requescie leci reload nginx,
certbot i drugi reload — dlatego ta komenda ma timeout --timeout (domyslnie 120 s)
zamiast globalnych 15 s. Po odpowiedzi skrypt i tak dopytuje
GET /nginx/certificates/<id> az expires_on bedzie ustawione; jesli POST padnie na
timeoucie klienta, cert jest odszukiwany po domenach (certbot moze wciaz dzialac po
stronie serwera). Przy porazce challenge'u NPM kasuje wiersz certu i zwraca blad z
wyjsciem certbota — wtedy szukaj szczegolow w docker logs npm na docelowym node.
create-host opcje: --domain (powtarzalne), --forward-host, --forward-port,
--forward-scheme http|https (domyslnie http), --cert-id (domyslnie 0 = brak),
--ssl-forced/--no-ssl-forced (domyslnie: true jesli podano --cert-id),
--http2-support/--no-http2-support, --block-exploits/--no-block-exploits
(domyslnie true), --websocket/--no-websocket (domyslnie false),
--access-list-id, --advanced-config.
Przyklady
Faza 2 okit.pl — przepiecie certow proxy hostow na wildcard
Zamiast bulk-SQL + recznego sed na .conf (patrz
docs/sessions/2026-07-07-okit-wildcard.md), API robi reload samo:
# 1. znajdz ID wildcard certu
python3 scripts/npm/npm_api.py --npm piha list-certs
# 2. znajdz ID hosta ktory ma dostac nowy cert
python3 scripts/npm/npm_api.py --npm piha list-hosts
# 3. podejrzyj zmiane (dry-run)
python3 scripts/npm/npm_api.py --npm piha set-cert 11 5
# 4. wykonaj
python3 scripts/npm/npm_api.py --npm piha set-cert 11 5 --apply
Deploy Gokapi — vhost share.okit.pl na npm@VPS
# dry-run
python3 scripts/npm/npm_api.py --npm vps create-host \
--domain share.okit.pl \
--forward-host 127.0.0.1 --forward-port 8080 \
--cert-id 5 --ssl-forced --http2-support --block-exploits
# apply
python3 scripts/npm/npm_api.py --npm vps create-host \
--domain share.okit.pl \
--forward-host 127.0.0.1 --forward-port 8080 \
--cert-id 5 --ssl-forced --http2-support --block-exploits \
--apply
Cert dla narty27.kapala.org na npm@VPS
# 1. dry-run
python3 scripts/npm/npm_api.py --npm vps create-cert --domain narty27.kapala.org
# 2. zamow cert (HTTP-01; domena musi wskazywac A-rekordem na publiczny IP VPS)
python3 scripts/npm/npm_api.py --npm vps create-cert --domain narty27.kapala.org --apply
# 3. podepnij pod host 14 + wymus HTTPS
python3 scripts/npm/npm_api.py --npm vps set-cert --host-id 14 --cert-id <ID> --ssl-forced --apply
Obsluga bledow
Bledy autentykacji, brakujace hosty/certy i bledy API zwracane sa z czytelnym komunikatem na stderr (kod wyjscia 1) — np.:
Error: PUT /nginx/proxy-hosts/11 -> HTTP 404: Proxy host not found
Referencje API
Oficjalny swagger jest niekompletny; zweryfikowano bezposrednio ze zrodla
(GET /api/schema na dzialacej instancji NPM 2.14, OpenAPI 3.1) oraz
github.com/DenAV/nginx-proxy-manager-ansible.