Metadata-Version: 2.4
Name: portwyrm
Version: 0.1.0a9
Summary: A self-hosted, npmctl-compatible reverse proxy control plane and UI.
Author: Groupsum
License-Expression: Apache-2.0
Project-URL: Homepage, https://github.com/groupsum/portwyrm
Project-URL: Repository, https://github.com/groupsum/portwyrm
Project-URL: Issues, https://github.com/groupsum/portwyrm/issues
Classifier: Development Status :: 2 - Pre-Alpha
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Python: <3.15,>=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: argon2-cffi<26,>=25.1
Requires-Dist: bcrypt<6,>=4
Requires-Dist: cryptography<51,>=50.0.0
Requires-Dist: psycopg[binary]<4,>=3.2
Requires-Dist: pyjwt[crypto]<3,>=2.10
Requires-Dist: pyotp<3,>=2.9
Requires-Dist: sqlalchemy<3,>=2.0.51
Requires-Dist: tigrbl[postgres]<0.5,>=0.4.4
Requires-Dist: uvicorn<1,>=0.35
Dynamic: license-file

# Portwyrm

Portwyrm is a self-hosted reverse proxy control plane with a built-in web UI, designed to
replace Nginx Proxy Manager while remaining compatible with npmctl's current API contract.

The `1.0.0` MVP target is literal p100 coverage of the frozen compatibility envelope. Early
alpha, beta, and release-candidate versions are milestones toward that target, not claims of
partial MVP completion.

## Status

The frozen S0-S5 runtime scope is under active implementation on `master`: composed Python
CLI/API/UIX, deterministic Nginx protocols, durable identity and MFA, certificate lifecycle,
portable configuration, NPM migration, npmctl-compatible plan/apply/drift/audit behavior, and live
PostgreSQL restart persistence have executable coverage. External ACME and MySQL restart
conformance remain fail-closed release gates; implementation does not imply a published `1.0.0`.

## Development

```shell
uv sync --dev
uv run ruff check .
uv run ruff format --check .
uv run pytest
uv run ssot-registry validate . --write-report
```

Run the development control plane and open `http://localhost:81/ui/`:

```shell
uv run portwyrm --host 127.0.0.1 --port 81
```

The container exposes two deliberately separate network surfaces:

- port `81` is the control plane: its built-in UI lives at `/ui/`, alongside the administration
  APIs and health endpoints;
- ports `80` and `443` are the Nginx data plane for configured proxy traffic and do not serve a
  second administration UI.

On a fresh container data volume, Portwyrm creates the initial superuser as
`admin@example.com` with a deployment-specific one-time password. Read that password from the
first-start container log. The account cannot access control-plane resources until the UI's
mandatory password-change ceremony succeeds. The plaintext bootstrap file is removed after the
change commits. Set `PORTWYRM_INITIAL_ADMIN_EMAIL` and `PORTWYRM_INITIAL_ADMIN_PASSWORD` to supply
your own bootstrap credentials; automatic bootstrap credentials are never embedded in the image.

The same package includes an operator CLI. It speaks the npmctl-compatible API, accepts a
token through `--token` or `PORTWYRM_TOKEN`, and prints stable JSON for automation:

```shell
uv run portwyrm setup --email admin@example.com --password 'change-me-now'
uv run portwyrm login --email admin@example.com --password 'change-me-now'
uv run portwyrm status
uv run portwyrm list proxy-hosts --token "$PORTWYRM_TOKEN"
uv run portwyrm create proxy-hosts --token "$PORTWYRM_TOKEN" --data proxy-host.json
```

`serve`, `status`, `schema`, `setup`, `login`, `list`, `get`, `create`, `update`, `delete`,
`export`, `import`, `npm-preflight`, and `npm-import` are available without Node.js or npm.

The UI is packaged as standards-based browser assets. Node.js and npm are not required to
build, install, deploy, or operate Portwyrm.

## Compatibility principles

- Preserve the NPM-shaped `/api` surface used by npmctl.
- Keep compatibility DTOs separate from native domain models.
- Preserve IDs and npmctl owner metadata during import and round trips.
- Compile deterministic Nginx generations, validate them, activate atomically, and retain a
  last-known-good rollback target.
- Use Tigrbl engines for memory, SQLite, and PostgreSQL metadata. MySQL/MariaDB requires the
  separately published synchronous `tigrbl_engine_mysql` plugin; filesystem/object
  storage holds certificate and immutable generated-config artifacts
  with explicit consistency and high-availability boundaries.

## Deliberate boundaries

- mTLS and HTTP/3 termination remain out of the frozen NPM-compatible `1.0.0` scope.
- WebTransport termination is not provided by Nginx. The optional QUIC gateway performs opaque hostname routing and leaves TLS/QUIC/WebTransport termination to the backend.
- Portwyrm never requires Node.js or npm to install, build, deploy, or operate.

Licensed under Apache-2.0.

## Opaque QUIC hostname passthrough

`compose.quic-gateway.yaml` runs Portwyrm as the sole host UDP/443 publisher while Nginx Proxy Manager continues to own TCP/443. The gateway decrypts only the QUIC Initial metadata needed to read SNI and ALPN, chooses an enabled `quic_passthrough_host`, and forwards every datagram without terminating TLS. The backend therefore presents its own certificate and owns the HTTP/3/WebTransport session.

The native API exposes authenticated capability discovery at `/api/v2/capabilities` and owner-scoped CRUD at `/api/v2/quic-passthrough-hosts`. Wyrmctl is the supported declarative controller for these resources. Unknown SNI, unsupported ALPN, malformed Initial packets, and direct-IP traffic have no route. Application Compose stacks expose container UDP ports only; they never publish host UDP ports.
