add support for deployment in subfolder

configurable using BASE_PATH env variable
This commit is contained in:
Jakub Blažej 2021-12-17 20:21:47 +01:00
parent 0ca68f791f
commit 8cf827e6e1
8 changed files with 34 additions and 19 deletions

View file

@ -7,6 +7,7 @@ const postcssRTLCSS = require("postcss-rtlcss");
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({
base: "./",
plugins: [ plugins: [
vue(), vue(),
legacy({ legacy({

View file

@ -1,17 +1,18 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<base href="/" >
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"> <link rel="apple-touch-icon" sizes="180x180" href="./apple-touch-icon.png">
<link rel="icon" type="image/svg+xml" href="/icon.svg" /> <link rel="icon" type="image/svg+xml" href="./icon.svg" />
<link rel="manifest" href="/manifest.json" /> <link rel="manifest" href="./manifest.json" />
<meta name="theme-color" id="theme-color" content="" /> <meta name="theme-color" id="theme-color" content="" />
<meta name="description" content="Uptime Kuma monitoring tool" /> <meta name="description" content="Uptime Kuma monitoring tool" />
<title>Uptime Kuma</title> <title>Uptime Kuma</title>
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>
<script type="module" src="/src/main.js"></script> <script type="module" src="./src/main.js"></script>
</body> </body>
</html> </html>

View file

@ -1,7 +1,7 @@
{ {
"name": "Uptime Kuma", "name": "Uptime Kuma",
"short_name": "Uptime Kuma", "short_name": "Uptime Kuma",
"start_url": "/", "start_url": "./",
"background_color": "#fff", "background_color": "#fff",
"display": "standalone", "display": "standalone",
"icons": [ "icons": [

View file

@ -76,6 +76,8 @@ if (hostname) {
const port = parseInt(process.env.UPTIME_KUMA_PORT || process.env.PORT || args.port || 3001); const port = parseInt(process.env.UPTIME_KUMA_PORT || process.env.PORT || args.port || 3001);
const basePath = process.env.UPTIME_KUMA_BASE_PATH || process.env.BASE_PATH || '/'
// SSL // SSL
const sslKey = process.env.UPTIME_KUMA_SSL_KEY || process.env.SSL_KEY || args["ssl-key"] || undefined; const sslKey = process.env.UPTIME_KUMA_SSL_KEY || process.env.SSL_KEY || args["ssl-key"] || undefined;
const sslCert = process.env.UPTIME_KUMA_SSL_CERT || process.env.SSL_CERT || args["ssl-cert"] || undefined; const sslCert = process.env.UPTIME_KUMA_SSL_CERT || process.env.SSL_CERT || args["ssl-cert"] || undefined;
@ -113,7 +115,7 @@ if (sslKey && sslCert) {
server = http.createServer(app); server = http.createServer(app);
} }
const io = new Server(server); const io = new Server(server, {path: basePath + '/socket.io'});
module.exports.io = io; module.exports.io = io;
// Must be after io instantiation // Must be after io instantiation
@ -165,6 +167,7 @@ let indexHTML = "";
try { try {
indexHTML = fs.readFileSync("./dist/index.html").toString(); indexHTML = fs.readFileSync("./dist/index.html").toString();
indexHTML = indexHTML.replace(/\<base href.*?\>/, `<base href="${basePath}">`);
} catch (e) { } catch (e) {
// "dist/index.html" is not necessary for development // "dist/index.html" is not necessary for development
if (process.env.NODE_ENV !== "development") { if (process.env.NODE_ENV !== "development") {
@ -180,6 +183,8 @@ exports.entryPage = "dashboard";
await initDatabase(testMode); await initDatabase(testMode);
exports.entryPage = await setting("entryPage"); exports.entryPage = await setting("entryPage");
const mainRouter = express.Router();
console.log("Adding route"); console.log("Adding route");
@ -188,16 +193,16 @@ exports.entryPage = "dashboard";
// *************************** // ***************************
// Entry Page // Entry Page
app.get("/", async (_request, response) => { mainRouter.get("/", async (_request, response) => {
if (exports.entryPage === "statusPage") { if (exports.entryPage === "statusPage") {
response.redirect("/status"); response.redirect("status");
} else { } else {
response.redirect("/dashboard"); response.redirect("dashboard");
} }
}); });
// Robots.txt // Robots.txt
app.get("/robots.txt", async (_request, response) => { mainRouter.get("/robots.txt", async (_request, response) => {
let txt = "User-agent: *\nDisallow:"; let txt = "User-agent: *\nDisallow:";
if (! await setting("searchEngineIndex")) { if (! await setting("searchEngineIndex")) {
txt += " /"; txt += " /";
@ -210,29 +215,31 @@ exports.entryPage = "dashboard";
// Prometheus API metrics /metrics // Prometheus API metrics /metrics
// With Basic Auth using the first user's username/password // With Basic Auth using the first user's username/password
app.get("/metrics", basicAuth, prometheusAPIMetrics()); mainRouter.get("/metrics", basicAuth, prometheusAPIMetrics());
app.use("/", express.static("dist")); mainRouter.use("/", express.static("dist"));
// ./data/upload // ./data/upload
app.use("/upload", express.static(Database.uploadDir)); mainRouter.use("/upload", express.static(Database.uploadDir));
app.get("/.well-known/change-password", async (_, response) => { mainRouter.get("/.well-known/change-password", async (_, response) => {
response.redirect("https://github.com/louislam/uptime-kuma/wiki/Reset-Password-via-CLI"); response.redirect("https://github.com/louislam/uptime-kuma/wiki/Reset-Password-via-CLI");
}); });
// API Router // API Router
const apiRouter = require("./routers/api-router"); const apiRouter = require("./routers/api-router");
app.use(apiRouter); mainRouter.use(apiRouter);
// Universal Route Handler, must be at the end of all express routes. // Universal Route Handler, must be at the end of all express routes.
app.get("*", async (_request, response) => { mainRouter.get("*", async (_request, response) => {
if (_request.originalUrl.startsWith("/upload/")) { if (_request.originalUrl.startsWith("/upload/")) {
response.status(404).send("File not found."); response.status(404).send("File not found.");
} else { } else {
response.send(indexHTML); response.send(indexHTML);
} }
}); });
app.use(basePath, mainRouter);
console.log("Adding socket handler"); console.log("Adding socket handler");
io.on("connection", async (socket) => { io.on("connection", async (socket) => {

View file

@ -90,7 +90,7 @@ module.exports.statusPageSocketHandler = (socket) => {
// Convert to file // Convert to file
await ImageDataURI.outputFile(imgDataUrl, Database.uploadDir + "logo.png"); await ImageDataURI.outputFile(imgDataUrl, Database.uploadDir + "logo.png");
config.logo = "/upload/logo.png?t=" + Date.now(); config.logo = "./upload/logo.png?t=" + Date.now();
} else { } else {
config.icon = imgDataUrl; config.icon = imgDataUrl;

View file

@ -19,9 +19,9 @@
<ul class="nav nav-pills"> <ul class="nav nav-pills">
<li class="nav-item me-2"> <li class="nav-item me-2">
<a href="/status" class="nav-link status-page"> <router-link href="/status" class="nav-link status-page">
<font-awesome-icon icon="stream" /> {{ $t("Status Page") }} <font-awesome-icon icon="stream" /> {{ $t("Status Page") }}
</a> </router-link>
</li> </li>
<li v-if="$root.loggedIn" class="nav-item me-2"> <li v-if="$root.loggedIn" class="nav-item me-2">
<router-link to="/dashboard" class="nav-link"> <router-link to="/dashboard" class="nav-link">

View file

@ -67,8 +67,11 @@ export default {
wsHost = protocol + location.host; wsHost = protocol + location.host;
} }
const urlBase = document.querySelector("head base").getAttribute("href");
socket = io(wsHost, { socket = io(wsHost, {
transports: ["websocket"], transports: ["websocket"],
path: urlBase + "/socket.io"
}); });
socket.on("info", (info) => { socket.on("info", (info) => {

3
vue.config.js Normal file
View file

@ -0,0 +1,3 @@
module.exports = {
publicPath: './',
}