fix: use effective_domain for service links and clean up stale DNS records
Unit Tests / test (push) Successful in 11m32s

Dashboard, Email, Calendar, and Files pages were building service URLs
with the internal LAN zone name (e.g. 'cell') instead of the public
effective domain (e.g. 'pic2.pic.ngo'), and always using http:// even
in DDNS mode where HTTPS is available.

Changes:
- Dashboard/Email/Calendar/Files: read effective_domain + domain_mode
  from ConfigContext; use effective_domain in non-LAN mode and https://
  for all DDNS domain modes.
- Calendar: show port 443 instead of 80 in DDNS mode.
- network_manager.update_split_horizon_zone: when the primary internal
  zone name is a parent of the effective DDNS domain (e.g. pic.ngo is a
  parent of pic2.pic.ngo), remove stale bootstrap service records (api,
  calendar, files, mail, webmail, webdav) that pollute the DNS display
  and would shadow public DNS responses.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-28 05:06:52 -04:00
parent d7dbd596ab
commit 66500bb128
6 changed files with 83 additions and 26 deletions
+10 -8
View File
@@ -31,8 +31,10 @@ function InfoRow({ label, value }) {
}
function Calendar() {
const { domain = 'cell', service_ips = {}, service_configs = {} } = useConfig();
const cellHost = `calendar.${domain}`;
const { domain = 'cell', effective_domain, domain_mode = 'lan', service_ips = {}, service_configs = {} } = useConfig();
const svcDomain = (domain_mode !== 'lan' && effective_domain) ? effective_domain : domain;
const proto = domain_mode === 'lan' ? 'http' : 'https';
const cellHost = `calendar.${svcDomain}`;
const calendarIp = service_ips.vip_calendar || '172.20.0.21';
const dnsIp = service_ips.dns || '172.20.0.3';
const calendarPort = service_configs.calendar?.port ?? 5232;
@@ -85,10 +87,10 @@ function Calendar() {
Use these settings in your calendar / contacts app (iOS, Android, Thunderbird, etc.)
</p>
<div className="bg-gray-50 rounded-lg px-4 py-2">
<InfoRow label="Server URL" value={`http://${cellHost}`} />
<InfoRow label="CalDAV path" value={`http://${cellHost}/`} />
<InfoRow label="CardDAV path" value={`http://${cellHost}/`} />
<InfoRow label="Port" value="80" />
<InfoRow label="Server URL" value={`${proto}://${cellHost}`} />
<InfoRow label="CalDAV path" value={`${proto}://${cellHost}/`} />
<InfoRow label="CardDAV path" value={`${proto}://${cellHost}/`} />
<InfoRow label="Port" value={domain_mode === 'lan' ? '80' : '443'} />
<InfoRow label="Direct IP" value={calendarIp} />
<InfoRow label="Direct port" value={String(calendarPort)} />
<InfoRow label="Protocol" value="HTTP (CalDAV/CardDAV)" />
@@ -118,7 +120,7 @@ function Calendar() {
<p className="font-medium text-gray-900 mb-1">Android (DAVx⁵ app)</p>
<ol className="list-decimal ml-4 space-y-0.5 text-xs text-gray-600">
<li>Install DAVx⁵ from Play Store / F-Droid</li>
<li>Login with URL: <span className="font-mono">http://{cellHost}/</span></li>
<li>Login with URL: <span className="font-mono">{proto}://{cellHost}/</span></li>
<li>Select calendars &amp; address books to sync</li>
</ol>
</div>
@@ -126,7 +128,7 @@ function Calendar() {
<p className="font-medium text-gray-900 mb-1">Thunderbird</p>
<ol className="list-decimal ml-4 space-y-0.5 text-xs text-gray-600">
<li>Calendar New Calendar On the Network</li>
<li>Format: CalDAV, Location: <span className="font-mono">http://{cellHost}/</span></li>
<li>Format: CalDAV, Location: <span className="font-mono">{proto}://{cellHost}/</span></li>
</ol>
</div>
</div>
+7 -5
View File
@@ -21,12 +21,14 @@ import { useConfig } from '../contexts/ConfigContext';
function Dashboard({ isOnline }) {
const navigate = useNavigate();
const { domain = 'cell', cell_name = 'mycell' } = useConfig();
const { domain = 'cell', cell_name = 'mycell', effective_domain, domain_mode = 'lan' } = useConfig();
const svcDomain = (domain_mode !== 'lan' && effective_domain) ? effective_domain : domain;
const proto = domain_mode === 'lan' ? 'http' : 'https';
const SERVICES = [
{ name: 'Cell Home', url: `http://${cell_name}.${domain}`, desc: 'Main UI — no login needed' },
{ name: 'Calendar', url: `http://calendar.${domain}`, desc: 'Use your configured account credentials' },
{ name: 'Files', url: `http://files.${domain}`, desc: 'Use your configured account credentials' },
{ name: 'Webmail', url: `http://mail.${domain}`, desc: 'Use your configured account credentials' },
{ name: 'Cell Home', url: domain_mode === 'lan' ? `http://${cell_name}.${domain}` : `https://${svcDomain}`, desc: 'Main UI — no login needed' },
{ name: 'Calendar', url: `${proto}://calendar.${svcDomain}`, desc: 'Use your configured account credentials' },
{ name: 'Files', url: `${proto}://files.${svcDomain}`, desc: 'Use your configured account credentials' },
{ name: 'Webmail', url: `${proto}://mail.${svcDomain}`, desc: 'Use your configured account credentials' },
];
const [cellStatus, setCellStatus] = useState(null);
const [servicesStatus, setServicesStatus] = useState(null);
+6 -4
View File
@@ -31,8 +31,10 @@ function InfoRow({ label, value }) {
}
function Email() {
const { domain = 'cell', service_ips = {}, service_configs = {} } = useConfig();
const cellHost = `mail.${domain}`;
const { domain = 'cell', effective_domain, domain_mode = 'lan', service_ips = {}, service_configs = {} } = useConfig();
const svcDomain = (domain_mode !== 'lan' && effective_domain) ? effective_domain : domain;
const proto = domain_mode === 'lan' ? 'http' : 'https';
const cellHost = `mail.${svcDomain}`;
const emailCfg = service_configs.email || {};
const mailIp = service_ips.vip_mail || '172.20.0.23';
const dnsIp = service_ips.dns || '172.20.0.3';
@@ -113,8 +115,8 @@ function Email() {
<h3 className="text-lg font-medium text-gray-900">Webmail</h3>
</div>
<div className="bg-gray-50 rounded-lg px-4 py-2">
<InfoRow label="URL" value={`http://mail.${domain}`} />
<InfoRow label="Alt URL" value={`http://webmail.${domain}`} />
<InfoRow label="URL" value={`${proto}://mail.${svcDomain}`} />
<InfoRow label="Alt URL" value={`${proto}://webmail.${svcDomain}`} />
<InfoRow label="Direct IP" value={`http://${mailIp}`} />
<InfoRow label="Direct port" value={String(webmailPort)} />
</div>
+11 -9
View File
@@ -31,9 +31,11 @@ function InfoRow({ label, value }) {
}
function Files() {
const { domain = 'cell', service_ips = {}, service_configs = {} } = useConfig();
const filesHost = `files.${domain}`;
const webdavHost = `webdav.${domain}`;
const { domain = 'cell', effective_domain, domain_mode = 'lan', service_ips = {}, service_configs = {} } = useConfig();
const svcDomain = (domain_mode !== 'lan' && effective_domain) ? effective_domain : domain;
const proto = domain_mode === 'lan' ? 'http' : 'https';
const filesHost = `files.${svcDomain}`;
const webdavHost = `webdav.${svcDomain}`;
const filesIp = service_ips.vip_files || '172.20.0.22';
const webdavIp = service_ips.vip_webdav || '172.20.0.24';
const filesCfg = service_configs.files || {};
@@ -85,7 +87,7 @@ function Files() {
<h3 className="text-lg font-medium text-gray-900">Web file manager</h3>
</div>
<div className="bg-gray-50 rounded-lg px-4 py-2">
<InfoRow label="URL" value={`http://${filesHost}`} />
<InfoRow label="URL" value={`${proto}://${filesHost}`} />
<InfoRow label="Direct IP" value={`http://${filesIp}`} />
<InfoRow label="Direct port" value={String(filegatorPort)} />
</div>
@@ -101,7 +103,7 @@ function Files() {
<h3 className="text-lg font-medium text-gray-900">WebDAV (mount as drive)</h3>
</div>
<div className="bg-gray-50 rounded-lg px-4 py-2">
<InfoRow label="URL" value={`http://${webdavHost}`} />
<InfoRow label="URL" value={`${proto}://${webdavHost}`} />
<InfoRow label="Direct IP" value={`http://${webdavIp}`} />
<InfoRow label="Direct port" value={String(webdavPort)} />
<InfoRow label="Auth" value="Basic (user / password)" />
@@ -120,19 +122,19 @@ function Files() {
<div className="space-y-3 text-sm">
<div>
<p className="font-medium text-gray-900 mb-1">macOS (Finder)</p>
<p className="text-xs text-gray-600">Go Connect to Server <span className="font-mono">http://{webdavHost}</span></p>
<p className="text-xs text-gray-600">Go Connect to Server <span className="font-mono">{proto}://{webdavHost}</span></p>
</div>
<div>
<p className="font-medium text-gray-900 mb-1">Windows</p>
<p className="text-xs text-gray-600">Map Network Drive <span className="font-mono">\\{webdavHost}\DavWWWRoot</span> or use <span className="font-mono">http://{webdavHost}</span> in "Connect to a Web Site"</p>
<p className="text-xs text-gray-600">Map Network Drive <span className="font-mono">\\{webdavHost}\DavWWWRoot</span> or use <span className="font-mono">{proto}://{webdavHost}</span> in "Connect to a Web Site"</p>
</div>
<div>
<p className="font-medium text-gray-900 mb-1">iOS (Files app)</p>
<p className="text-xs text-gray-600">Files ... Connect to Server <span className="font-mono">http://{webdavHost}</span></p>
<p className="text-xs text-gray-600">Files ... Connect to Server <span className="font-mono">{proto}://{webdavHost}</span></p>
</div>
<div>
<p className="font-medium text-gray-900 mb-1">Android</p>
<p className="text-xs text-gray-600">Use <strong>Solid Explorer</strong> or <strong>FX File Explorer</strong> Add cloud WebDAV <span className="font-mono">http://{webdavHost}</span></p>
<p className="text-xs text-gray-600">Use <strong>Solid Explorer</strong> or <strong>FX File Explorer</strong> Add cloud WebDAV <span className="font-mono">{proto}://{webdavHost}</span></p>
</div>
</div>
</div>