Add env var SETUP_PORT to change the default port (#174263)

This commit is contained in:
Robert Resch
2026-07-02 09:31:04 +00:00
parent 1e8e23d70a
commit 72a2a88fea
4 changed files with 75 additions and 5 deletions
+2 -3
View File
@@ -33,7 +33,6 @@ from homeassistant.const import (
EVENT_HOMEASSISTANT_START,
EVENT_HOMEASSISTANT_STOP,
HASSIO_USER_NAME,
SERVER_PORT,
)
from homeassistant.core import Event, HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
@@ -60,7 +59,7 @@ from homeassistant.util.json import json_loads
from .auth import async_setup_auth
from .ban import setup_bans
from .config import async_load_config
from .config import async_load_config, default_server_port
from .const import ( # noqa: F401
CONF_BASE_URL,
CONF_CORS_ORIGINS,
@@ -109,7 +108,7 @@ HTTP_SCHEMA: Final = vol.All(
vol.Optional(CONF_SERVER_HOST): vol.All(
cv.ensure_list, vol.Length(min=1), [cv.string]
),
vol.Optional(CONF_SERVER_PORT, default=SERVER_PORT): cv.port,
vol.Optional(CONF_SERVER_PORT, default=default_server_port): cv.port,
vol.Optional(CONF_BASE_URL): cv.string,
vol.Optional(CONF_SSL_CERTIFICATE): cv.isfile,
vol.Optional(CONF_SSL_PEER_CERTIFICATE): cv.isfile,
+25 -1
View File
@@ -3,6 +3,7 @@
import asyncio
from ipaddress import IPv4Network, IPv6Network, ip_network
import logging
import os
from typing import Any, Final, TypedDict, cast, override
import voluptuous as vol
@@ -31,6 +32,7 @@ from .const import (
CONF_USE_X_FRAME_OPTIONS,
DEFAULT_CORS,
DOMAIN,
ENV_SETUP_PORT,
NO_LOGIN_ATTEMPT_THRESHOLD,
SSL_INTERMEDIATE,
SSL_MODERN,
@@ -38,6 +40,28 @@ from .const import (
_LOGGER = logging.getLogger(__name__)
def default_server_port() -> int:
"""Return the default HTTP server port.
The built-in default port can be overridden via the
``SETUP_PORT`` environment variable. An invalid value is ignored in favor
of the built-in default.
"""
if (env_value := os.environ.get(ENV_SETUP_PORT)) is None:
return SERVER_PORT
try:
return cast(int, cv.port(env_value))
except vol.Invalid:
_LOGGER.warning(
"Invalid port %r in %s environment variable; falling back to %s",
env_value,
ENV_SETUP_PORT,
SERVER_PORT,
)
return SERVER_PORT
STORAGE_KEY: Final = DOMAIN
STORAGE_VERSION: Final = 2
@@ -86,7 +110,7 @@ HTTP_STORAGE_SCHEMA: Final = vol.Schema(
vol.Optional(CONF_SERVER_HOST): vol.All(
cv.ensure_list, vol.Length(min=1), [cv.string]
),
vol.Optional(CONF_SERVER_PORT, default=SERVER_PORT): cv.port,
vol.Optional(CONF_SERVER_PORT, default=default_server_port): cv.port,
vol.Optional(CONF_SSL_CERTIFICATE): cv.isfile,
vol.Optional(CONF_SSL_PEER_CERTIFICATE): cv.isfile,
vol.Optional(CONF_SSL_KEY): cv.isfile,
+2
View File
@@ -28,6 +28,8 @@ CONF_SSL_PROFILE: Final = "ssl_profile"
SSL_MODERN: Final = "modern"
SSL_INTERMEDIATE: Final = "intermediate"
ENV_SETUP_PORT: Final = "SETUP_PORT"
# Cast to be able to load custom cards.
# My to be able to check url and version info.
DEFAULT_CORS: Final[list[str]] = ["https://cast.home-assistant.io"]
+46 -1
View File
@@ -15,7 +15,12 @@ from homeassistant.auth.providers.homeassistant import HassAuthProvider
from homeassistant.components import cloud, http
from homeassistant.components.cloud import CloudNotAvailable
from homeassistant.components.http import DOMAIN
from homeassistant.components.http.config import _DEFAULT_CONFIG, HTTP_STORAGE_SCHEMA
from homeassistant.components.http.config import (
_DEFAULT_CONFIG,
HTTP_STORAGE_SCHEMA,
default_server_port,
)
from homeassistant.components.http.const import ENV_SETUP_PORT
from homeassistant.const import HASSIO_USER_NAME
from homeassistant.core import HomeAssistant
from homeassistant.helpers import issue_registry as ir
@@ -1191,6 +1196,46 @@ async def test_setup_migrates_v1_storage_to_v2(
assert data["yaml_migration_done"] is True
@pytest.mark.parametrize(
("env", "expected_port"),
[
pytest.param({}, 8123, id="unset"),
pytest.param({ENV_SETUP_PORT: "80"}, 80, id="valid"),
pytest.param({ENV_SETUP_PORT: "0"}, 8123, id="out-of-range"),
pytest.param({ENV_SETUP_PORT: "notaport"}, 8123, id="not-a-number"),
pytest.param({ENV_SETUP_PORT: ""}, 8123, id="empty"),
],
)
def test_default_server_port(
env: dict[str, str],
expected_port: int,
) -> None:
"""Test SETUP_PORT overrides the default port and invalid values fall back."""
with patch.dict(os.environ, env, clear=True):
assert default_server_port() == expected_port
async def test_setup_port_env_var_used_as_default(
hass: HomeAssistant,
hass_storage: dict[str, Any],
) -> None:
"""Test SETUP_PORT is used as the default server port without YAML config."""
mock_server = Mock()
with (
patch.dict(os.environ, {ENV_SETUP_PORT: "80"}),
patch(
"asyncio.BaseEventLoop.create_server", return_value=mock_server
) as mock_create_server,
):
assert await async_setup_component(hass, "http", {})
await hass.async_start()
await hass.async_block_till_done()
args, _ = mock_create_server.call_args
assert args[2] == 80
assert hass_storage["http"]["data"]["pending"]["server_port"] == 80
async def test_websocket_http_config(
hass: HomeAssistant,
hass_ws_client: WebSocketGenerator,