From 21040d7d4c00e001f9a0b7195d7f978fb98c23ce Mon Sep 17 00:00:00 2001 From: Nico <47644445+nicotsx@users.noreply.github.com> Date: Mon, 5 Jan 2026 07:07:35 +0100 Subject: [PATCH] feat: detect if a custom docker hostname was set before defaulting to zerobyte (#298) --- README.md | 2 +- app/server/core/config.ts | 27 +++++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9ee4f1eb..2b91dfb8 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ Zerobyte can be customized using environment variables. Below are the available | Variable | Description | Default | | :-------------------- | :------------------------------------------------------------------------------------------------------------ | :--------- | | `PORT` | The port the web interface and API will listen on. | `4096` | -| `RESTIC_HOSTNAME` | The hostname used by Restic when creating snapshots. Useful for identifying which machine a backup came from. | `zerobyte` | +| `RESTIC_HOSTNAME` | The hostname used by Restic when creating snapshots. Automatically detected if a custom hostname is set in Docker. | `zerobyte` | | `LOG_LEVEL` | Logging verbosity. Options: `debug`, `info`, `warn`, `error`. | `info` | | `SERVER_IDLE_TIMEOUT` | Idle timeout for the server in seconds. | `60` | | `TZ` | Timezone for the container (e.g., `Europe/Paris`). **Crucial for accurate backup scheduling.** | `UTC` | diff --git a/app/server/core/config.ts b/app/server/core/config.ts index 7e3ef811..38d09bec 100644 --- a/app/server/core/config.ts +++ b/app/server/core/config.ts @@ -1,11 +1,34 @@ +import { readFileSync } from "node:fs"; +import os from "node:os"; import { type } from "arktype"; import "dotenv/config"; +const getResticHostname = () => { + try { + const mountinfo = readFileSync("/proc/self/mountinfo", "utf-8"); + const hostnameLine = mountinfo.split("\n").find((line) => line.includes(" /etc/hostname ")); + const hostname = os.hostname(); + + if (hostnameLine) { + const containerIdMatch = hostnameLine.match(/[0-9a-f]{64}/); + const containerId = containerIdMatch ? containerIdMatch[0] : null; + + if (containerId?.startsWith(hostname)) { + return "zerobyte"; + } + + return hostname || "zerobyte"; + } + } catch {} + + return "zerobyte"; +}; + const envSchema = type({ NODE_ENV: type.enumerated("development", "production", "test").default("production"), SERVER_IP: 'string = "localhost"', SERVER_IDLE_TIMEOUT: 'string.integer.parse = "60"', - RESTIC_HOSTNAME: "string = 'zerobyte'", + RESTIC_HOSTNAME: "string?", PORT: 'string.integer.parse = "4096"', MIGRATIONS_PATH: "string?", APP_VERSION: "string = 'dev'", @@ -14,7 +37,7 @@ const envSchema = type({ environment: s.NODE_ENV, serverIp: s.SERVER_IP, serverIdleTimeout: s.SERVER_IDLE_TIMEOUT, - resticHostname: s.RESTIC_HOSTNAME, + resticHostname: s.RESTIC_HOSTNAME || getResticHostname(), port: s.PORT, migrationsPath: s.MIGRATIONS_PATH, appVersion: s.APP_VERSION,