feature: bootstrap diagnostics on port 17081 during the first setup.
Release / release (push) Successful in 13s

This commit is contained in:
slawek committed 2026-10-24 10:07:22 +02:00
1 parent 2e2bacee7d
commit c0cd323a0c
13 files changed
+275 -181

No files matched your search

+44 -1
View File
@@ -5,6 +5,12 @@ Regenerates the configuration files first, then does everything that needs
the live system: routes, DNS-derived identity, WireGuard keys, firewall rules
and service reloads. Idempotent - a second run changes nothing.
Until a run has succeeded (SETUP_DONE), every run starts the bootstrap
services, BOOTSTRAP_UNITS, which show the progress and the failure recorded in
SETUP_STATE on BOOTSTRAP_PORTS, and the firewall opens those ports on the
internal interface. The first successful run writes SETUP_DONE, closes the
ports and stops the bootstrap services; a failed run leaves them running.
Interface names come from the configuration and are never guessed. The
firewall and NAT rules are written against them, so choosing the wrong one
would be a silent and security-relevant mistake.
@@ -30,9 +36,16 @@ UFW_DEFAULTS = pathlib.Path('/etc/default/ufw')
WG_DIR = pathlib.Path('/etc/wireguard')
WEB_STATE = pathlib.Path('/run/vpn-router/web.json')
#: The state, the current step and the failure of the last run, which the web service shows while it starts.
#: The state, the current step and the failure of the last run, which the bootstrap services show.
SETUP_STATE = pathlib.Path('/run/vpn-router/setup.json')
#: Written once a run has succeeded; until then setup runs the bootstrap services and opens their ports.
SETUP_DONE = pathlib.Path('/var/lib/vpn-router/setup.done')
#: The units of the bootstrap services, and their ports: the Router Manager's and the router's.
BOOTSTRAP_UNITS = ('vpn-router-bootstrap.service', 'vpn-router-manager-bootstrap.service')
BOOTSTRAP_PORTS = (17080, 17081)
#: The Router Manager, vpn-router-manager, when it is installed, and its settings.
MANAGER = pathlib.Path('/usr/lib/vpn-router-manager/manager')
MANAGER_CONFIG = pathlib.Path('/etc/vpn-router-manager/manager.json')
@@ -49,6 +62,7 @@ BLOCKS = (
('# OPENVPN RULES START', '# OPENVPN RULES END'),
('# P2S DNS RULES START', '# P2S DNS RULES END'),
('# WEB RULES START', '# WEB RULES END'),
('# BOOTSTRAP RULES START', '# BOOTSTRAP RULES END'),
('# MANAGER RULES START', '# MANAGER RULES END'),
('# ROUTER FORWARD RULES START', '# ROUTER FORWARD RULES END'),
('# ROUTER NAT RULES START', '# ROUTER NAT RULES END'),
@@ -202,6 +216,14 @@ def filter_block(ctx):
'# WEB RULES END',
]
if not SETUP_DONE.exists() and ctx['int_iface']:
lines += [
'',
'# BOOTSTRAP RULES START',
*(f'-A ufw-before-input -i {ctx["int_iface"]} -p tcp --dport {port} -j ACCEPT' for port in BOOTSTRAP_PORTS),
'# BOOTSTRAP RULES END',
]
if MANAGER.exists() and ctx['int_iface']:
port = manager_port()
lines += [
@@ -448,7 +470,27 @@ def progress(state, step, error=None):
}) + '\n', encoding='utf-8')
def start_bootstrap():
"""Start the bootstrap services while no run has succeeded; a unit that is not installed is skipped."""
if not SETUP_DONE.exists():
for unit in BOOTSTRAP_UNITS:
run(['systemctl', 'start', '--no-block', unit], check=False)
def end_bootstrap(ctx):
"""After the first successful run: write SETUP_DONE, close the bootstrap ports and stop the bootstrap services."""
if SETUP_DONE.exists():
return
SETUP_DONE.parent.mkdir(parents=True, exist_ok=True)
SETUP_DONE.touch()
if setup_ufw(ctx):
run(['ufw', 'reload'], check=False)
for unit in BOOTSTRAP_UNITS:
run(['systemctl', 'stop', unit], check=False)
def main():
start_bootstrap()
progress('running', 'configuration')
cfg = vpnrouter.load_config()
ctx, changed = vpnrouter.configure(cfg)
@@ -511,6 +553,7 @@ def main():
print(f'vpn-router: error: {problem}', file=sys.stderr)
return 1
progress('done', 'done')
end_bootstrap(ctx)
return 0