When an HTTPS service is already running with a listen-address bound to a VRF interface, adding or modifying the vrf configuration fails with:
[ service https ] TCP port "443" is used by another service! [[service https]] failed Commit failed
This is also the case after a reboot of VyOS, where the https API previously configured with a VRF will fail to repopulate in the config and give errors about config parsing at boot.
No other service is using port 443. The same configuration works on older VyOS rolling builds (2025.11.29-1320-rolling).
Steps to Reproduce:
Configure HTTPS with a listen-address on a VRF interface:
set service https api keys id MYKEY key 'myapikey' set service https api rest set service https certificates certificate MYCERT set service https certificates ca-certificate MYCA set service https listen-address 192.168.140.21 commit
Then add the VRF:
set service https vrf OOB-Management commit
The commit at step 2 fails. If listen-address is removed first, adding vrf alone succeeds.
Expected Behavior: The commit should succeed. The VRF and listen-address are compatible — nginx will bind inside the VRF namespace.
Actual Behavior: Commit fails with the port conflict error.
Root Cause Analysis:
The bug is in src/conf_mode/service_https.py in the verify() function (around line 93):
for address in listen_address:
if not check_port_availability(address, port, 'tcp') and \
not is_listen_port_bind_service(port, 'nginx'):
raise ConfigError(f'TCP port "{port}" is used by another service!')Two VRF-related issues combine:
check_port_availability() (python/vyos/utils/network.py) performs a socket.bind() test in the default VRF/namespace, regardless of the target VRF. When listen-address points to an IP on a VRF interface (e.g., 192.168.140.21 on OOB-Management), the address doesn't exist in the default namespace, so the bind fails with OSError. The function returns False (port unavailable), which is incorrect — the port isn't in use, the address simply isn't reachable from the default namespace.
is_listen_port_bind_service() uses psutil.net_connections() to check if nginx holds the port. If nginx is already running inside the VRF namespace, psutil may not see its sockets from the default namespace context. The function returns False (nginx not found), so the safety fallback fails too.
The combination of both returning False triggers the ConfigError incorrectly.
Suggested Fix:
Skip the port availability check when a VRF is configured, since the check runs in the wrong namespace and cannot produce a valid result:
# Skip port check when VRF is configured — the verify process runs
# in the default namespace and cannot bind/see ports in other VRFs.
if 'vrf' not in https:
for address in listen_address:
if not check_port_availability(address, port, 'tcp') and \
not is_listen_port_bind_service(port, 'nginx'):
raise ConfigError(f'TCP port "{port}" is used by another service!')A more comprehensive fix would be to make check_port_availability() VRF-aware (running the socket bind inside the target VRF via ip vrf exec), but skipping the check for VRF-bound services is the simpler and safer approach.
Workaround:
Configure the VRF without a listen-address first, then add the listen-address in a subsequent commit. Or set both listen-address and vrf simultaneously in the same commit (order-dependent workaround) after already committing the HTTPS API.