This release is a pre-release and may not be stable for production use.
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
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/:
uv run portwyrm --host 127.0.0.1 --port 81
The container exposes two deliberately separate network surfaces:
- port
81is the control plane: its built-in UI lives at/ui/, alongside the administration APIs and health endpoints; - ports
80and443are 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:
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
/apisurface 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_mysqlplugin; filesystem/object storage holds certificate and immutable generated-config artifacts with explicit consistency and high-availability boundaries.
Deliberate boundaries
- mTLS and HTTP/3/QUIC remain out of the frozen
1.0.0scope. - WebTransport is not supported by the selected Nginx OSS data plane and is intentionally absent.
- Portwyrm never requires Node.js or npm to install, build, deploy, or operate.
Licensed under Apache-2.0.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file portwyrm-0.1.0a4.tar.gz.
File metadata
- Download URL: portwyrm-0.1.0a4.tar.gz
- Upload date:
- Size: 684.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
50939e6390ba804cea3b5f326e0b7c09600366f9093a6bbb5857b7b4db7b7f11
|
|
| MD5 |
21f5c55d079abd7cc5394889ba06e9ff
|
|
| BLAKE2b-256 |
22452e28890469568e90fd2cf3f46a9ed85a7bcb6ac9cf6e22008ed34343e995
|
File details
Details for the file portwyrm-0.1.0a4-py3-none-any.whl.
File metadata
- Download URL: portwyrm-0.1.0a4-py3-none-any.whl
- Upload date:
- Size: 710.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
88ca120a804fb101f982cc4a25a12904211eb61dfb36c25984b21387d05dac85
|
|
| MD5 |
79c22bca6aebf69a5937ac3ce18e2abc
|
|
| BLAKE2b-256 |
7285098be60bc4abc3cd5166a1e89e8050abaaab7404cd0385b0116f87b9ae2e
|