Add CA download to dashboard: GET /gateway/ca.crt + Gateway-panel button
When the gateway serves internal-CA HTTPS (gateway.tls=internal), other devices must trust Caddy's root CA to accept *.lan HTTPS. Surface that from the dashboard instead of hand-copying root.crt around. - API: GET /gateway/ca.crt returns the public root cert (PEM) as a download, sourced from Caddy's admin API (/pki/ca/local — matches the running gateway) with an on-disk root.crt fallback. 404 unless tls=internal. GatewayInfo gains `tls` and `ca_fingerprint` (SHA-256, for out-of-band verification). The CA private key is never exposed — only the public root. - UI: a "CA cert" button in the Gateway panel, shown only when tls=internal, linking to the download with the fingerprint in its tooltip. - Tests for the tls=off defaults and the 404-without-internal-tls path; docs note the button + endpoint.
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import { useMemo, useState } from "react"
|
||||
import { Link } from "react-router-dom"
|
||||
import { Globe, RefreshCw, FileText } from "lucide-react"
|
||||
import { Globe, RefreshCw, FileText, ShieldCheck } from "lucide-react"
|
||||
import type { GatewayInfo, HealthStatus } from "@/types"
|
||||
import { useGatewayReload, useCaddyfile } from "@/services/api/hooks"
|
||||
import { apiClient } from "@/services/api/client"
|
||||
import { HealthBadge } from "./HealthBadge"
|
||||
|
||||
interface GatewayPanelProps {
|
||||
@@ -33,6 +34,20 @@ export function GatewayPanel({ gateway, statuses }: GatewayPanelProps) {
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
{gateway.tls === "internal" && (
|
||||
<a
|
||||
href={apiClient.streamUrl("/gateway/ca.crt")}
|
||||
download="castle-root.crt"
|
||||
className="flex items-center gap-1 text-xs px-2.5 py-1 rounded bg-[var(--border)] hover:bg-[var(--border)]/80 text-[var(--muted)] hover:text-[var(--foreground)] transition-colors"
|
||||
title={
|
||||
"Download the gateway's root CA — install on other devices to trust *.lan HTTPS" +
|
||||
(gateway.ca_fingerprint ? `\nSHA-256: ${gateway.ca_fingerprint}` : "")
|
||||
}
|
||||
>
|
||||
<ShieldCheck size={12} />
|
||||
CA cert
|
||||
</a>
|
||||
)}
|
||||
<button
|
||||
onClick={() => reload()}
|
||||
disabled={reloading}
|
||||
|
||||
@@ -124,6 +124,8 @@ export interface GatewayInfo {
|
||||
service_count: number
|
||||
managed_count: number
|
||||
routes: GatewayRoute[]
|
||||
tls?: string | null // "internal" → host routes served over HTTPS by Caddy's local CA
|
||||
ca_fingerprint?: string | null // SHA-256 of the downloadable root CA
|
||||
}
|
||||
|
||||
export interface ServiceActionResponse {
|
||||
|
||||
Reference in New Issue
Block a user