feat: Introduce DashboardCNameRecord for custom domain handling in dashboards

This commit is contained in:
Nawaz Dhandala
2026-03-26 16:38:06 +00:00
parent c92e259978
commit b5bf1d6dd1
10 changed files with 51 additions and 18 deletions

View File

@@ -12,7 +12,7 @@ import FormFieldSchemaType from "Common/UI/Components/Forms/Types/FormFieldSchem
import ConfirmModal from "Common/UI/Components/Modal/ConfirmModal";
import ModelTable from "Common/UI/Components/ModelTable/ModelTable";
import FieldType from "Common/UI/Components/Types/FieldType";
import { APP_API_URL, StatusPageCNameRecord } from "Common/UI/Config";
import { APP_API_URL, DashboardCNameRecord } from "Common/UI/Config";
import API from "Common/UI/Utils/API/API";
import ModelAPI from "Common/UI/Utils/ModelAPI/ModelAPI";
import Navigation from "Common/UI/Utils/Navigation";
@@ -69,7 +69,7 @@ const DashboardCustomDomains: FunctionComponent<PageComponentProps> = (
isEditable={true}
cardProps={{
title: "Custom Domains",
description: `Important: Please add a CNAME record pointing to ${StatusPageCNameRecord} for these domains for this to work.`,
description: `Important: Please add a CNAME record pointing to ${DashboardCNameRecord} for these domains for this to work.`,
}}
refreshToggle={refreshToggle}
onBeforeCreate={(
@@ -325,7 +325,7 @@ const DashboardCustomDomains: FunctionComponent<PageComponentProps> = (
<ConfirmModal
title={`Add CNAME`}
description={
StatusPageCNameRecord ? (
DashboardCNameRecord ? (
<div>
<span>
Please add CNAME record to your domain. Details of
@@ -344,7 +344,7 @@ const DashboardCustomDomains: FunctionComponent<PageComponentProps> = (
<br />
<span>
<b>Content: </b>
{StatusPageCNameRecord}
{DashboardCNameRecord}
</span>
<br />
<br />
@@ -360,10 +360,10 @@ const DashboardCustomDomains: FunctionComponent<PageComponentProps> = (
installation. Please contact your server admin to
enable this feature. To enable this feature, if you
are using Docker compose, the
<b>STATUS_PAGE_CNAME_RECORD</b> environment variable
<b>DASHBOARD_CNAME_RECORD</b> environment variable
must be set when starting the OneUptime cluster. If
you are using Helm and Kubernetes then set
statusPage.cnameRecord in the values.yaml file.
dashboard.cnameRecord in the values.yaml file.
</span>
</div>
)
@@ -418,7 +418,7 @@ const DashboardCustomDomains: FunctionComponent<PageComponentProps> = (
<ConfirmModal
title={`Order Free SSL Certificate for this Dashboard`}
description={
StatusPageCNameRecord ? (
DashboardCNameRecord ? (
<div>
Please click on the button below to order SSL for this
domain. We will use LetsEncrypt to order a certificate.

View File

@@ -1,4 +1,4 @@
import { StatusPageCNameRecord } from "../EnvironmentConfig";
import { DashboardCNameRecord } from "../EnvironmentConfig";
import UserMiddleware from "../Middleware/UserAuthorization";
import DashboardDomainService, {
Service as DashboardDomainServiceType,
@@ -35,7 +35,7 @@ export default class DashboardDomainAPI extends BaseAPI<
next: NextFunction,
) => {
try {
if (!StatusPageCNameRecord) {
if (!DashboardCNameRecord) {
return Response.sendErrorResponse(
req,
res,
@@ -131,7 +131,7 @@ export default class DashboardDomainAPI extends BaseAPI<
next: NextFunction,
) => {
try {
if (!StatusPageCNameRecord) {
if (!DashboardCNameRecord) {
return Response.sendErrorResponse(
req,
res,

View File

@@ -35,6 +35,7 @@ const FRONTEND_ENV_ALLOW_LIST: Array<string> = [
"VAPID_SUBJECT",
"VERSION",
"STATUS_PAGE_CNAME_RECORD",
"DASHBOARD_CNAME_RECORD",
"ANALYTICS_KEY",
"ANALYTICS_HOST",
"GIT_SHA",
@@ -252,6 +253,9 @@ export const ClickhouseHost: Hostname = Hostname.fromString(
export const StatusPageCNameRecord: string =
process.env["STATUS_PAGE_CNAME_RECORD"] || "";
export const DashboardCNameRecord: string =
process.env["DASHBOARD_CNAME_RECORD"] || "";
export const ClickhousePort: Port = new Port(
process.env["CLICKHOUSE_PORT"] || "8123",
);

View File

@@ -19,7 +19,7 @@ import DashboardDomain from "../../Models/DatabaseModels/DashboardDomain";
import AcmeCertificateService from "./AcmeCertificateService";
import Telemetry, { Span } from "../Utils/Telemetry";
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
import { StatusPageCNameRecord } from "../EnvironmentConfig";
import { DashboardCNameRecord } from "../EnvironmentConfig";
import Domain from "../Types/Domain";
export class Service extends DatabaseService<DashboardDomain> {
@@ -367,7 +367,7 @@ export class Service extends DatabaseService<DashboardDomain> {
}
try {
if (StatusPageCNameRecord) {
if (DashboardCNameRecord) {
const cnameRecords: Array<string> = await Domain.getCnameRecords({
domain: fullDomain,
});
@@ -379,7 +379,7 @@ export class Service extends DatabaseService<DashboardDomain> {
if (!cnameRecord) {
logger.debug(
`No CNAME record found for ${fullDomain}. Expected record: ${StatusPageCNameRecord}`,
`No CNAME record found for ${fullDomain}. Expected record: ${DashboardCNameRecord}`,
);
await this.updateCnameStatusForDashboardDomain({
domain: fullDomain,
@@ -391,10 +391,10 @@ export class Service extends DatabaseService<DashboardDomain> {
if (
cnameRecord &&
cnameRecord.trim().toLocaleLowerCase() ===
StatusPageCNameRecord.trim().toLocaleLowerCase()
DashboardCNameRecord.trim().toLocaleLowerCase()
) {
logger.debug(
`CNAME record for ${fullDomain} matches the expected record: ${StatusPageCNameRecord}`,
`CNAME record for ${fullDomain} matches the expected record: ${DashboardCNameRecord}`,
);
await this.updateCnameStatusForDashboardDomain({
@@ -406,7 +406,7 @@ export class Service extends DatabaseService<DashboardDomain> {
}
logger.debug(
`CNAME record for ${fullDomain} is ${cnameRecord} and it does not match the expected record: ${StatusPageCNameRecord}`,
`CNAME record for ${fullDomain} is ${cnameRecord} and it does not match the expected record: ${DashboardCNameRecord}`,
);
}
} catch (err) {

View File

@@ -200,6 +200,9 @@ export const SubscriptionPlans: Array<SubscriptionPlan> =
export const StatusPageCNameRecord: string =
env("STATUS_PAGE_CNAME_RECORD") || "";
export const DashboardCNameRecord: string =
env("DASHBOARD_CNAME_RECORD") || "";
export const AnalyticsKey: string = env("ANALYTICS_KEY") || "";
export const AnalyticsHost: string = env("ANALYTICS_HOST");

View File

@@ -72,6 +72,8 @@ Usage:
value: {{ ternary "true" "false" $provisionSSL | quote }}
- name: STATUS_PAGE_CNAME_RECORD
value: {{ $.Values.statusPage.cnameRecord }}
- name: DASHBOARD_CNAME_RECORD
value: {{ $.Values.dashboard.cnameRecord | default "" }}
- name: ALLOWED_ACTIVE_MONITOR_COUNT_IN_FREE_PLAN
value: {{ $.Values.billing.allowedActiveMonitorCountInFreePlan | quote }}
- name: LOG_LEVEL

View File

@@ -784,6 +784,15 @@
},
"additionalProperties": false
},
"dashboard": {
"type": "object",
"properties": {
"cnameRecord": {
"type": ["string", "null"]
}
},
"additionalProperties": false
},
"probes": {
"type": "object",
"patternProperties": {

View File

@@ -324,6 +324,14 @@ alerts:
statusPage:
cnameRecord:
# If you would like to attach public dashboards to custom domains use this setting.
# Works the same way as statusPage.cnameRecord but for dashboards.
# For example, if you want dashboard.yourcompany.com to show a public dashboard:
# 1. Set the dashboard.cnameRecord to "oneuptime.yourcompany.com"
# 2. Create CNAME record in your DNS provider with the name "dashboard.yourcompany.com" and value "oneuptime.yourcompany.com"
dashboard:
cnameRecord:
probes:
one:
name: "Probe"

View File

@@ -36,14 +36,20 @@ GLOBAL_PROBE_2_KEY=probe-2-please-change-this-to-random-value
STATUS_PAGE_HTTPS_PORT=443
# If you would like to attach status pages or public dashboards to custom domains use this setting.
# If you would like to attach status pages to custom domains use this setting.
# For example, lets say you would like the status page to be hosted on status.yourcompany.com, then
# 1. Create a A record in your DNS provider with the name "oneuptime.yourcompany.com" and value to Public IP of the server oneuptime is deployed on.
# 2. Set the STATUS_PAGE_CNAME_RECORD to "oneuptime.yourcompany.com"
# 3. Create CNAME record in your DNS provider with the name "status.yourcompany.com" and value "oneuptime.yourcompany.com"
# This same CNAME is used for both status page and public dashboard custom domains.
STATUS_PAGE_CNAME_RECORD=oneuptime.yourcompany.com
# If you would like to attach public dashboards to custom domains use this setting.
# Works the same way as STATUS_PAGE_CNAME_RECORD but for dashboards.
# For example, if you want dashboard.yourcompany.com to show a public dashboard:
# 1. Set the DASHBOARD_CNAME_RECORD to "oneuptime.yourcompany.com"
# 2. Create CNAME record in your DNS provider with the name "dashboard.yourcompany.com" and value "oneuptime.yourcompany.com"
DASHBOARD_CNAME_RECORD=oneuptime.yourcompany.com
# --------------------------------------------- #
# You can safely ignore anything below this line. Keep them as default to make things work.

View File

@@ -6,6 +6,7 @@ x-common-variables: &common-variables
HTTP_PROTOCOL: ${HTTP_PROTOCOL}
STATUS_PAGE_CNAME_RECORD: ${STATUS_PAGE_CNAME_RECORD}
DASHBOARD_CNAME_RECORD: ${DASHBOARD_CNAME_RECORD}
LOG_LEVEL: ${LOG_LEVEL}