feat: Add configurable defaults via NPM_PROXY_DEFAULTS env var

- Add NPM_PROXY_DEFAULTS JSON environment variable for default settings
- Merge user overrides with base defaults (certificate_id, ssl_forced, etc.)
- Update create_proxy_host to use None defaults and pull from config
- Update env.example with documentation and examples
This commit is contained in:
Ben
2025-12-24 15:30:03 +00:00
parent 69158a871b
commit e8df05e3f3
3 changed files with 85 additions and 23 deletions

View File

@@ -7,3 +7,8 @@ NPM_SECRET=changeme
NPM_MCP_HOST=0.0.0.0
NPM_MCP_PORT=8000
NPM_MCP_TRANSPORT=stdio # stdio or http
# Proxy Host Creation Defaults (JSON)
# Set default values for create_proxy_host tool parameters
# Example with wildcard cert: NPM_PROXY_DEFAULTS='{"certificate_id": 24, "ssl_forced": true}'
# NPM_PROXY_DEFAULTS='{"certificate_id": 0, "ssl_forced": true, "block_exploits": true, "allow_websocket_upgrade": true}'

View File

@@ -1,7 +1,21 @@
"""Configuration management using pydantic-settings."""
from typing import Any
from pydantic import field_validator
from pydantic_settings import BaseSettings, SettingsConfigDict
# Default values for proxy host creation
DEFAULT_PROXY_SETTINGS: dict[str, Any] = {
"forward_scheme": "http",
"certificate_id": 0,
"ssl_forced": True,
"block_exploits": True,
"allow_websocket_upgrade": True,
"access_list_id": 0,
"advanced_config": "",
}
class Settings(BaseSettings):
"""Application settings loaded from environment variables."""
@@ -23,5 +37,30 @@ class Settings(BaseSettings):
mcp_port: int = 8000
mcp_transport: str = "stdio" # "stdio" or "http"
# Proxy host creation defaults (JSON string)
# Example: '{"certificate_id": 24, "ssl_forced": true}'
proxy_defaults: dict[str, Any] = {}
@field_validator("proxy_defaults", mode="before")
@classmethod
def parse_proxy_defaults(cls, v: Any) -> dict[str, Any]:
"""Parse JSON string to dict, or pass through if already dict."""
if isinstance(v, dict):
return v
if isinstance(v, str) and v.strip():
import json
try:
return json.loads(v)
except json.JSONDecodeError as e:
raise ValueError(f"Invalid JSON in NPM_PROXY_DEFAULTS: {e}") from e
return {}
def get_proxy_defaults(self) -> dict[str, Any]:
"""Get merged proxy defaults (base defaults + user overrides)."""
merged = DEFAULT_PROXY_SETTINGS.copy()
merged.update(self.proxy_defaults)
return merged
settings = Settings()

View File

@@ -291,13 +291,13 @@ async def create_proxy_host(
domain_names: list[str],
forward_host: str,
forward_port: int,
forward_scheme: str = "http",
certificate_id: int = 0,
ssl_forced: bool = True,
block_exploits: bool = True,
allow_websocket_upgrade: bool = True,
access_list_id: int = 0,
advanced_config: str = "",
forward_scheme: str | None = None,
certificate_id: int | None = None,
ssl_forced: bool | None = None,
block_exploits: bool | None = None,
allow_websocket_upgrade: bool | None = None,
access_list_id: int | None = None,
advanced_config: str | None = None,
) -> str:
"""Create a new proxy host in Nginx Proxy Manager.
@@ -305,18 +305,22 @@ async def create_proxy_host(
domain_names: List of domain names (e.g., ["app.ext.ben.io"])
forward_host: Backend host/IP to forward to (e.g., "192.168.1.100" or "container-name")
forward_port: Backend port to forward to (e.g., 8080)
forward_scheme: Backend protocol - "http" or "https" (default: "http")
forward_scheme: Backend protocol - "http" or "https" (default from config)
certificate_id: SSL certificate ID. Use list_certificates to find available certs.
Use 0 for no SSL, or the ID of a matching wildcard cert.
ssl_forced: Force HTTPS redirect (default: True)
block_exploits: Enable common exploit blocking (default: True)
allow_websocket_upgrade: Allow WebSocket connections (default: True)
Use 0 for no SSL, or the ID of a wildcard cert. (default from config)
ssl_forced: Force HTTPS redirect (default from config)
block_exploits: Enable common exploit blocking (default from config)
allow_websocket_upgrade: Allow WebSocket connections (default from config)
access_list_id: Access list ID for authentication. Use list_access_lists to find.
Use 0 for no access restrictions (default: 0)
advanced_config: Custom nginx configuration block (default: "")
Use 0 for no access restrictions. (default from config)
advanced_config: Custom nginx configuration block (default from config)
Returns:
JSON with created proxy host details including the new host ID.
Details of the created proxy host including the new host ID.
Note:
Default values can be configured via NPM_PROXY_DEFAULTS environment variable.
Example: NPM_PROXY_DEFAULTS='{"certificate_id": 24, "ssl_forced": true}'
Example:
create_proxy_host(
@@ -324,22 +328,36 @@ async def create_proxy_host(
forward_host="10.0.0.50",
forward_port=3000,
certificate_id=24, # *.ext.ben.io wildcard
ssl_forced=True
)
"""
try:
# Get defaults from config, then override with provided values
defaults = settings.get_proxy_defaults()
client = get_client()
host = await client.create_proxy_host(
domain_names=domain_names,
forward_host=forward_host,
forward_port=forward_port,
forward_scheme=forward_scheme,
certificate_id=certificate_id,
ssl_forced=ssl_forced,
block_exploits=block_exploits,
allow_websocket_upgrade=allow_websocket_upgrade,
access_list_id=access_list_id,
advanced_config=advanced_config,
forward_scheme=forward_scheme
if forward_scheme is not None
else defaults["forward_scheme"],
certificate_id=certificate_id
if certificate_id is not None
else defaults["certificate_id"],
ssl_forced=ssl_forced if ssl_forced is not None else defaults["ssl_forced"],
block_exploits=block_exploits
if block_exploits is not None
else defaults["block_exploits"],
allow_websocket_upgrade=allow_websocket_upgrade
if allow_websocket_upgrade is not None
else defaults["allow_websocket_upgrade"],
access_list_id=access_list_id
if access_list_id is not None
else defaults["access_list_id"],
advanced_config=advanced_config
if advanced_config is not None
else defaults["advanced_config"],
)
domains = ", ".join(host.domain_names)