feat(panel-access): provision Caddy bridge proxy for panel-access

This commit is contained in:
KodekaTeam committed 2026-07-11 22:13:54 +07:00
1 parent c1bf6af7ee
commit 4507640e8f
1 file changed
+37 -11
+37 -11
View File
@@ -9,8 +9,8 @@ const execFileAsync = promisify(execFile);
const PANEL_PROBE_TIMEOUT_MS = 12000;
const PANEL_HOST_ROOT = (process.env.PANEL_HOST_ROOT || "").replace(/\/+$/, "");
const PANEL_HOST_EXECUTION = process.env.PANEL_ACCESS_HOST_EXECUTION === "1";
const PANEL_PROXY_NETWORK = process.env.PANEL_PROXY_NETWORK || "doktainer-proxy";
const DOCKER_SOCKET_PATH = process.env.DOCKER_SOCKET_PATH || "/var/run/docker.sock";
const PANEL_PROXY_NETWORK = (process.env.PANEL_PROXY_NETWORK || "doktainer-proxy").trim();
const DEFAULT_DOCKER_SOCKET_PATH = "/var/run/docker.sock";
export type PanelProxyType = "NGINX" | "CADDY" | "TRAEFIK";
@@ -112,6 +112,16 @@ function panelHostPath(path: string) {
: path;
}
function resolveDockerSocketPath() {
const candidates = [
process.env.DOCKER_SOCKET_PATH,
DEFAULT_DOCKER_SOCKET_PATH,
"/run/docker.sock",
].filter((value): value is string => Boolean(value));
return candidates.find((path) => existsSync(path)) ?? candidates[0];
}
function resolvePanelUpstream() {
return (
process.env.PANEL_UPSTREAM_URL ||
@@ -523,22 +533,34 @@ async function probeDockerBridgeProxyStack(): Promise<DockerProxyStackProbe> {
traefik: emptyDockerProxyProbe(null),
});
if (!existsSync(DOCKER_SOCKET_PATH)) return unavailable();
try {
const docker = new Dockerode({ socketPath: DOCKER_SOCKET_PATH });
const socketPath = resolveDockerSocketPath();
if (!socketPath || !existsSync(socketPath)) {
const requested = process.env.DOCKER_SOCKET_PATH || DEFAULT_DOCKER_SOCKET_PATH;
throw new Error(`Docker socket is not available at ${requested}.`);
}
const docker = new Dockerode({ socketPath });
const containers = await docker.listContainers({ all: true });
const result = unavailable();
for (const type of ["NGINX", "CADDY", "TRAEFIK"] as const) {
const container = containers.find((candidate) => {
const candidates = containers.filter((candidate) => {
const name = candidate.Names?.[0]?.replace(/^\//, "") || "";
const onProxyNetwork = Boolean(candidate.NetworkSettings?.Networks?.[PANEL_PROXY_NETWORK]);
return onProxyNetwork && proxyMatchesContainer(type, name, candidate.Image || "");
return proxyMatchesContainer(type, name, candidate.Image || "");
});
if (!container) continue;
const inspected = await Promise.all(
candidates.map(async (candidate) => ({
candidate,
details: await docker.getContainer(candidate.Id).inspect(),
})),
);
const match = inspected.find(({ details }) =>
Boolean(details.NetworkSettings.Networks?.[PANEL_PROXY_NETWORK]),
);
if (!match) continue;
const details = await docker.getContainer(container.Id).inspect();
const { candidate: container, details } = match;
const key = type.toLowerCase() as Lowercase<PanelProxyType>;
result[key] = {
installed: true,
@@ -567,7 +589,11 @@ async function runDockerContainerShell(
timeoutMs = 20000,
): Promise<ShellResult> {
try {
const docker = new Dockerode({ socketPath: DOCKER_SOCKET_PATH });
const socketPath = resolveDockerSocketPath();
if (!socketPath || !existsSync(socketPath)) {
throw new Error("Docker socket is not available to the Doktainer app.");
}
const docker = new Dockerode({ socketPath });
const execution = await docker.getContainer(containerId).exec({
AttachStdout: true,
AttachStderr: true,