Prompt for server binding, port, and auth (root API key when remote). Auth mode is auto-detected by the server from ``root_api_key``: setting a key switches to ``api_key`` mode, no key means ``dev`` mode (which the server only permits on localhost) — so this step never writes ``auth
(current: dict[str, Any] | None = None)
| 1617 | |
| 1618 | |
| 1619 | def _wizard_server(current: dict[str, Any] | None = None) -> dict[str, Any] | None: |
| 1620 | """Prompt for server binding, port, and auth (root API key when remote). |
| 1621 | |
| 1622 | Auth mode is auto-detected by the server from ``root_api_key``: setting a |
| 1623 | key switches to ``api_key`` mode, no key means ``dev`` mode (which the |
| 1624 | server only permits on localhost) — so this step never writes |
| 1625 | ``auth_mode`` explicitly. *current* (the existing server config, if any) |
| 1626 | seeds all defaults so an update run can keep values by pressing Enter. |
| 1627 | """ |
| 1628 | current = current or {} |
| 1629 | _rule("Server & auth") |
| 1630 | if current: |
| 1631 | print(f" {_dim('Current: ' + _summarize_server(current))}") |
| 1632 | print(f" {_dim('Local: only this machine can reach the server (no auth, dev mode).')}") |
| 1633 | print(f" {_dim('Remote: bind to 0.0.0.0 for Docker / LAN access — requires API-key auth.')}") |
| 1634 | |
| 1635 | is_remote_now = str(current.get("host") or "127.0.0.1") not in ( |
| 1636 | "127.0.0.1", |
| 1637 | "localhost", |
| 1638 | "::1", |
| 1639 | ) |
| 1640 | mode = _prompt_choice( |
| 1641 | "Bind server host to:", |
| 1642 | [ |
| 1643 | ("Local (127.0.0.1)", "(default, safer — no auth needed)"), |
| 1644 | ("Remote (0.0.0.0)", "(Docker / remote access — root API key required)"), |
| 1645 | ], |
| 1646 | default=2 if is_remote_now else 1, |
| 1647 | ) |
| 1648 | |
| 1649 | try: |
| 1650 | port_default = int(current.get("port") or 1933) |
| 1651 | except (TypeError, ValueError): |
| 1652 | port_default = 1933 |
| 1653 | port = _prompt_required_int("Port", default=port_default) |
| 1654 | if port is None: |
| 1655 | port = port_default |
| 1656 | |
| 1657 | if mode == 1: |
| 1658 | return {"host": "127.0.0.1", "port": port} |
| 1659 | |
| 1660 | print(f"\n {_dim('Non-local binding switches auth to api_key mode: every client must send')}") |
| 1661 | print(f" {_dim('the root API key as a Bearer token (Authorization: Bearer <key>).')}") |
| 1662 | |
| 1663 | existing_key = str(current.get("root_api_key") or "") |
| 1664 | key_options: list[tuple[str, str]] = [] |
| 1665 | if existing_key: |
| 1666 | key_options.append(("Keep existing key", f"({_mask_secret(existing_key)})")) |
| 1667 | key_options.append( |
| 1668 | ("Generate one for me", "(recommended — 64-char random key, shown once below)") |
| 1669 | ) |
| 1670 | key_options.append(("Enter my own", "")) |
| 1671 | |
| 1672 | key_source = _prompt_choice("Root API key:", key_options, default=1) |
| 1673 | offset = 1 if existing_key else 0 |
| 1674 | |
| 1675 | if existing_key and key_source == 1: |
| 1676 | root_api_key = existing_key |