mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
118 lines
3.5 KiB
TypeScript
118 lines
3.5 KiB
TypeScript
import Exec from "Common/Server/Utils/Execute";
|
|
import LocalFile from "Common/Server/Utils/LocalFile";
|
|
import logger from "Common/Server/Utils/Logger";
|
|
|
|
export interface EnsurePrimarySslOptions {
|
|
hostname: string;
|
|
forceReload?: boolean;
|
|
}
|
|
|
|
export default class NginxConfigurator {
|
|
private static readonly DEFAULT_CONF_PATH: string =
|
|
"/etc/nginx/conf.d/default.conf";
|
|
private static readonly ENVSUBST_SCRIPT_PATH: string =
|
|
"/etc/nginx/envsubst-on-templates.sh";
|
|
private static readonly NGINX_LOG_DIRECTORY: string = "/var/log/nginx";
|
|
private static readonly NGINX_ACCESS_LOG_PATH: string = `${NginxConfigurator.NGINX_LOG_DIRECTORY}/access.log`;
|
|
private static readonly NGINX_ERROR_LOG_PATH: string = `${NginxConfigurator.NGINX_LOG_DIRECTORY}/error.log`;
|
|
|
|
private static async ensureLogFiles(): Promise<void> {
|
|
try {
|
|
await LocalFile.makeDirectory(this.NGINX_LOG_DIRECTORY);
|
|
|
|
const accessLogExists: boolean = await LocalFile.doesFileExist(
|
|
this.NGINX_ACCESS_LOG_PATH,
|
|
);
|
|
|
|
if (!accessLogExists) {
|
|
await LocalFile.write(this.NGINX_ACCESS_LOG_PATH, "");
|
|
}
|
|
|
|
const errorLogExists: boolean = await LocalFile.doesFileExist(
|
|
this.NGINX_ERROR_LOG_PATH,
|
|
);
|
|
|
|
if (!errorLogExists) {
|
|
await LocalFile.write(this.NGINX_ERROR_LOG_PATH, "");
|
|
}
|
|
} catch (err) {
|
|
logger.error(
|
|
"[NginxConfigurator] Failed to ensure nginx log files exist before reload.",
|
|
);
|
|
logger.error(err);
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
public static async ensurePrimarySslConfigured(
|
|
options: EnsurePrimarySslOptions,
|
|
): Promise<void> {
|
|
const normalizedHost: string = options.hostname.trim().toLowerCase();
|
|
|
|
if (!normalizedHost) {
|
|
logger.warn(
|
|
"[NginxConfigurator] Cannot configure SSL because hostname is empty.",
|
|
);
|
|
return;
|
|
}
|
|
|
|
const certificateDirective: string = `ssl_certificate /etc/nginx/certs/ServerCerts/${normalizedHost}.crt;`;
|
|
|
|
let nginxConfig: string = "";
|
|
try {
|
|
nginxConfig = await LocalFile.read(this.DEFAULT_CONF_PATH);
|
|
} catch (err) {
|
|
logger.debug(
|
|
`[NginxConfigurator] Unable to read ${this.DEFAULT_CONF_PATH}; regenerating configuration.`,
|
|
);
|
|
logger.debug(err);
|
|
}
|
|
|
|
const templateHasDirective: boolean =
|
|
nginxConfig.includes(certificateDirective);
|
|
const shouldRefreshTemplate: boolean = !templateHasDirective;
|
|
const shouldReload: boolean =
|
|
options.forceReload === true || shouldRefreshTemplate;
|
|
|
|
if (!shouldReload) {
|
|
return;
|
|
}
|
|
|
|
const originalPrimaryDomain: string | undefined =
|
|
process.env["PRIMARY_DOMAIN"];
|
|
|
|
try {
|
|
process.env["PRIMARY_DOMAIN"] = normalizedHost;
|
|
|
|
if (shouldRefreshTemplate) {
|
|
await Exec.executeCommand(this.ENVSUBST_SCRIPT_PATH);
|
|
}
|
|
|
|
await this.ensureLogFiles();
|
|
await Exec.executeCommandInheritStdio({
|
|
command: "nginx",
|
|
args: ["-t", "-c", "/etc/nginx/nginx.conf"],
|
|
});
|
|
await Exec.executeCommandInheritStdio({
|
|
command: "nginx",
|
|
args: ["-s", "reload"],
|
|
});
|
|
logger.info(
|
|
`[NginxConfigurator] Reloaded nginx after updating certificate for ${normalizedHost}.`,
|
|
);
|
|
} catch (err) {
|
|
logger.error(
|
|
"[NginxConfigurator] Failed to reload nginx after certificate update.",
|
|
);
|
|
logger.error(err);
|
|
throw err;
|
|
} finally {
|
|
if (originalPrimaryDomain !== undefined) {
|
|
process.env["PRIMARY_DOMAIN"] = originalPrimaryDomain;
|
|
} else {
|
|
delete process.env["PRIMARY_DOMAIN"];
|
|
}
|
|
}
|
|
}
|
|
}
|