feat: route PIC services as subdomains of the cell's effective domain
Unit Tests / test (push) Successful in 11m33s
Unit Tests / test (push) Successful in 11m33s
In DDNS modes (pic_ngo, cloudflare, duckdns, http01), all built-in services are now reachable as subdomains of the cell domain, e.g. calendar.pic1.pic.ngo instead of pic1.pic.ngo/calendar. Key changes: - CaddyManager._build_core_service_routes(): new helper generates Caddy named-matcher host blocks for calendar, mail/webmail, files, webdav, and api subdomains within the wildcard TLS server block. - All ACME modes (pic_ngo, cloudflare, duckdns) use the new subdomain matchers; http01 emits a dedicated server block per service. - http01: installed store-plugin services whose name clashes with a core service are skipped to prevent duplicate server blocks. - routes/config.py: ip_utils.write_caddyfile() is skipped in non-LAN modes so LAN Caddy config never overwrites the ACME config. - firewall_manager.generate_corefile(): new split_horizon_zones param adds local authoritative file zones so LAN clients resolve *.pic1.pic.ngo to the internal Caddy IP without hairpin NAT. - NetworkManager.update_split_horizon_zone(): writes the wildcard zone file and regenerates the Corefile with the split-horizon block; called automatically after every identity change in non-LAN mode. - Added @ to allowed record-name chars in update_dns_zone validation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+34
-18
@@ -316,11 +316,12 @@ def update_config():
|
||||
net_result = network_manager.apply_domain(domain, reload=False)
|
||||
all_warnings.extend(net_result.get('warnings', []))
|
||||
_cur_id = config_manager.configs.get('_identity', {})
|
||||
ip_utils.write_caddyfile(
|
||||
_cur_id.get('ip_range', os.environ.get('CELL_IP_RANGE', '172.20.0.0/16')),
|
||||
_cur_id.get('cell_name', os.environ.get('CELL_NAME', 'mycell')),
|
||||
domain, '/app/config-caddy/Caddyfile'
|
||||
)
|
||||
if _cur_id.get('domain_mode', 'lan') == 'lan':
|
||||
ip_utils.write_caddyfile(
|
||||
_cur_id.get('ip_range', os.environ.get('CELL_IP_RANGE', '172.20.0.0/16')),
|
||||
_cur_id.get('cell_name', os.environ.get('CELL_NAME', 'mycell')),
|
||||
domain, '/app/config-caddy/Caddyfile'
|
||||
)
|
||||
_set_pending_restart(
|
||||
[f'domain changed to {domain}'],
|
||||
['dns', 'caddy'],
|
||||
@@ -334,12 +335,13 @@ def update_config():
|
||||
cn_result = network_manager.apply_cell_name(old_name, new_name, reload=False)
|
||||
all_warnings.extend(cn_result.get('warnings', []))
|
||||
_cur_id2 = config_manager.configs.get('_identity', {})
|
||||
ip_utils.write_caddyfile(
|
||||
_cur_id2.get('ip_range', os.environ.get('CELL_IP_RANGE', '172.20.0.0/16')),
|
||||
new_name,
|
||||
identity_updates.get('domain') or _cur_id2.get('domain', os.environ.get('CELL_DOMAIN', 'cell')),
|
||||
'/app/config-caddy/Caddyfile'
|
||||
)
|
||||
if _cur_id2.get('domain_mode', 'lan') == 'lan':
|
||||
ip_utils.write_caddyfile(
|
||||
_cur_id2.get('ip_range', os.environ.get('CELL_IP_RANGE', '172.20.0.0/16')),
|
||||
new_name,
|
||||
identity_updates.get('domain') or _cur_id2.get('domain', os.environ.get('CELL_DOMAIN', 'cell')),
|
||||
'/app/config-caddy/Caddyfile'
|
||||
)
|
||||
_set_pending_restart(
|
||||
[f'cell_name changed to {new_name}'],
|
||||
['dns'],
|
||||
@@ -370,7 +372,8 @@ def update_config():
|
||||
firewall_manager.ensure_caddy_virtual_ips()
|
||||
env_file = os.environ.get('COMPOSE_ENV_FILE', '/app/.env.compose')
|
||||
ip_utils.write_env_file(new_range, env_file, _collect_service_ports(config_manager.configs))
|
||||
ip_utils.write_caddyfile(new_range, cur_cell_name, cur_domain, '/app/config-caddy/Caddyfile')
|
||||
if cur_identity.get('domain_mode', 'lan') == 'lan':
|
||||
ip_utils.write_caddyfile(new_range, cur_cell_name, cur_domain, '/app/config-caddy/Caddyfile')
|
||||
_set_pending_restart(
|
||||
[f'ip_range changed to {new_range} — network will be recreated'],
|
||||
['*'], network_recreate=True,
|
||||
@@ -379,13 +382,25 @@ def update_config():
|
||||
|
||||
if identity_updates:
|
||||
_cur_identity = config_manager.configs.get('_identity', {})
|
||||
_eff_domain = config_manager.get_effective_domain()
|
||||
service_bus.publish_event(EventType.IDENTITY_CHANGED, 'config', {
|
||||
'cell_name': _cur_identity.get('cell_name'),
|
||||
'domain': _cur_identity.get('domain'),
|
||||
'domain_name': _cur_identity.get('domain_name'),
|
||||
'domain_mode': _cur_identity.get('domain_mode'),
|
||||
'effective_domain': config_manager.get_effective_domain(),
|
||||
'effective_domain': _eff_domain,
|
||||
})
|
||||
if _cur_identity.get('domain_mode', 'lan') != 'lan' and _eff_domain:
|
||||
try:
|
||||
import ip_utils as _ip_sh
|
||||
_ip_range = _cur_identity.get('ip_range', os.environ.get('CELL_IP_RANGE', '172.20.0.0/16'))
|
||||
_caddy_ip = _ip_sh.get_service_ips(_ip_range).get('caddy', '172.20.0.2')
|
||||
_primary_domain = _cur_identity.get('domain', os.environ.get('CELL_DOMAIN', 'cell'))
|
||||
network_manager.update_split_horizon_zone(
|
||||
_eff_domain, _caddy_ip, primary_domain=_primary_domain
|
||||
)
|
||||
except Exception as _sh_exc:
|
||||
logger.warning('split-horizon zone update failed: %s', _sh_exc)
|
||||
|
||||
_PORT_CHANGE_MAP = {
|
||||
('network', 'dns_port'): ('dns_port', ['dns']),
|
||||
@@ -644,11 +659,12 @@ def cancel_pending_config():
|
||||
if cur_cell_name and old_cell_name and cur_cell_name != old_cell_name:
|
||||
network_manager.apply_cell_name(cur_cell_name, old_cell_name, reload=False)
|
||||
|
||||
_ip_revert.write_caddyfile(
|
||||
_id.get('ip_range', os.environ.get('CELL_IP_RANGE', '172.20.0.0/16')),
|
||||
_id.get('cell_name', os.environ.get('CELL_NAME', 'mycell')),
|
||||
_dom, '/app/config-caddy/Caddyfile'
|
||||
)
|
||||
if _id.get('domain_mode', 'lan') == 'lan':
|
||||
_ip_revert.write_caddyfile(
|
||||
_id.get('ip_range', os.environ.get('CELL_IP_RANGE', '172.20.0.0/16')),
|
||||
_id.get('cell_name', os.environ.get('CELL_NAME', 'mycell')),
|
||||
_dom, '/app/config-caddy/Caddyfile'
|
||||
)
|
||||
|
||||
_clear_pending_restart()
|
||||
return jsonify({'message': 'Pending changes discarded'})
|
||||
|
||||
Reference in New Issue
Block a user