Repository navigation
feat(domains): add Domains page with DNS, certificate and Traefik error status - #60
Merged
Merged
Conversation
…or status Adds a Domains section (sidebar item and /dashboard/domains) that lists the domains of the active organization on the servers the caller can read, with each domain's DNS record, certificate and last Traefik error. It is an information page with no state changes: no buttons edit DNS, Traefik configuration, certificates or containers, and nothing restarts. For each server the page shows one row per domain: - the domain and the server it is on; - where it is used: links to the application or compose service that owns it (panel domains, including preview domains), or the container name and a link to the Docker containers view for a route that no panel service owns; - DNS status from node:dns (A and AAAA, 5 s timeout, cached for 10 minutes), with the resolved addresses, compared with the server's public address; - the certificate from Traefik's acme.json: expiry date and days left, red under 14 days and yellow under 30 days; a certificate that no route or panel domain uses is marked "certificate only, nothing uses it"; - the last Traefik error for the domain, with its time, the original line, a plain-language explanation and advice. Causes: no DNS record, no address record, Let's Encrypt timeout, port 443 answered by something other than Traefik (ALPN), port 443 closed or not reaching Traefik, rate limit, unknown. Explanations are in Russian and reuse docs/certificates-and-ports.md wording. Each server also has a Traefik log block with the last 300 certificate and ACME lines and a refresh button. Access: the same gate as the Traefik File System page and readTraefikFile. - domainOverview.list and domainOverview.traefikLogs are protectedProcedure and call checkPermission(traefikFiles: read), as settings.readTraefikFile does. - Each server gets the check readTraefikFile applies to it: the panel's own host needs owner or admin (assertLocalHostAccess); a remote server needs access to that server (assertSettingsServerAccess). Both helpers moved from settings.ts to server/api/utils/traefik-files-access.ts so the two routers share one implementation. A server the caller cannot read is not contacted, and its domains and routes are not listed. - acme.json is a protected file for readTraefikFile, so list reads it only when hasProtectedResourceAccess passes: owner or admin, browser session, open super session. Without that the page shows no certificate data and says so; the other columns still load. - The sidebar item and the page (getServerSideProps) check traefikFiles.read, as the Traefik page does. Both procedures are classified "read" in procedure-access.ts, the same as readTraefikFile. Private keys: acme.json contains keys. On the server, jq keeps only the domain names and the certificate field; without jq the whole file is read and the panel drops the keys before any other step touches the data. The keys are never returned, logged or put into an error message. Limits: - Every server read has a 15 s timeout and a server that does not answer shows an error entry without blocking the page. A slow server can still delay the first load by up to about 15 seconds. - docker logs is called with --since 168h (seven days), because Docker does not accept a day unit. - Wildcard names are not checked in DNS. - Domains that appear only in error lines of the Traefik log are shown as rows too, so the operator sees them. - The panel's own address comes from the Web Server IP setting when it is set, otherwise from public address detection (cached for 10 minutes). - Panel domains and route owners are not filtered by a member's service access list, and container names from route labels are shown without the docker read permission that guards the Docker view. The page follows the Traefik file gate only, not the overview's per-service scope. - Not verified against a running panel or against live servers; the tests mock every command, DNS call and database read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a read-only Domains page at
/dashboard/domains. It lists the domains of the active organization on each server the caller can read, with DNS status, certificate expiry, where the domain is used, and the last Traefik error.Base:
AgentHits-Dev. This PR does not depend on another open PR.What the page shows
node:dns(A and AAAA, 5 s timeout, 10 minute cache), compared with the server address.acme.json. Red under 14 days, yellow under 30 days.Access
The page uses the same gate as the Traefik File System page and
settings.readTraefikFile.domainOverview.listanddomainOverview.traefikLogsareprotectedProcedure. Both callcheckPermission({ traefikFiles: ["read"] }).settings.tstoserver/api/utils/traefik-files-access.ts, so both routers use one implementation.hasProtectedResourceAccess: owner or admin, browser session, and an open super session. Without it, the page shows no certificate data and a notice. The other columns still load.getServerSidePropschecktraefikFiles.read. Users without it are redirected to/.readinprocedure-access.ts, likereadTraefikFile.Members with the Traefik files permission can open the page, not only owners and admins.
Private keys
acme.jsoncontains keys. The server-side jq filter keeps only the domain names and the certificate field. Without jq, the whole file is read, and the panel drops the keys before anything else touches the data. Keys are never returned, logged, or put in an error message.The feature never reads container environment variables. Route discovery reads container names and labels only.
Test plan
apps/dokploy, domain-overview tests:bunx vitest run --config __test__/vitest.config.ts __test__/domain-overview. 7 files, 73 tests, all passing.checkPermissionand host checks against a fake member row.apps/dokploysuite on my local machine: 299 files, 3038 tests. 3028 passed, 4 failed, 6 skipped. The 4 failures are in__test__/deploy/application.real.test.ts, which runs real git clones and Docker builds. Docker is not running in my shell.pr-check (test)(bun run test): 299 of 299 files passed. 3037 tests passed, 1 skipped (3038). That run includesapplication.real.test.ts, and it passed.audit and typecheck,pr-check (build),main-image-smoke, and the threeservice-image-buildsjobs all passed.bunx tsc --noEmitpasses inpackages/serverand inapps/dokploy.bunx biome checkpasses on the 23 changed files.Not verified
🤖 Generated with Claude Code