Brakowalo certu dla narty27.kapala.org (host 14 na npm@VPS) — 443 zwracalo
tlsv1 unrecognized name. Proby POST /api/nginx/certificates z meta
{letsencrypt_email, letsencrypt_agree} konczyly sie 400 "data/meta must NOT
have additional properties".
Zweryfikowane w GET /api/schema oraz w /app/internal/certificate.js kontenera
(NPM 2.14.0): meta ma additionalProperties:false i nie zna pol email/agree.
Certbot dostaje --agree-tos na sztywno, a -m <email> z konta uzytkownika NPM.
Poprawny payload to {provider, domain_names, meta:{dns_challenge:false}}.
- create-cert --domain (powtarzalne), HTTP-01, dry-run domyslnie + --apply
- POST /nginx/certificates jest synchroniczne (reload + certbot + reload),
wiec ma wlasny timeout 120 s zamiast globalnych 15 s; po nim polling
GET /nginx/certificates/<id> az do expires_on, z czytelnym bledem po czasie
- gdy POST padnie na timeoucie klienta, cert jest odszukiwany po domenach
(certbot moze wciaz pracowac po stronie serwera)
- set-cert: przyjmuje takze --host-id/--cert-id obok pozycyjnych i umie
ustawic --ssl-forced przy tej samej zmianie
- README: schemat payloadu, skad bierze sie email, przyklad dla narty27
Cert #38 wystawiony (expires 2026-11-01), podpiety pod host 14 z ssl_forced;
https://narty27.kapala.org/viz.html -> 200, http -> 301.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
145 lines
5.7 KiB
Markdown
145 lines
5.7 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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-forced` ustawia 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:
|
|
|
|
```json
|
|
{"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:
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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`.
|