diff --git a/docker/.env.example b/docker/.env.example index 0db90aa23..1a1511f68 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -100,4 +100,13 @@ GID='1000' # PASSWORDUPPERCASE=1 # PASSWORDNUMERIC=1 # PASSWORDSYMBOL=1 -# PASSWORDREQUIREMENTS=4 \ No newline at end of file +# PASSWORDREQUIREMENTS=4 + +########################################### +######## ENABLE HTTPS SERVER ############## +########################################### +# By enabling this and providing the path/filename for the key and cert, +# the server will use HTTPS instead of HTTP. +#ENABLE_HTTPS="true" +#HTTPS_CERT_PATH="sslcert/cert.pem" +#HTTPS_KEY_PATH="sslcert/key.pem" diff --git a/server/.env.example b/server/.env.example index 07abed62f..93a1d7664 100644 --- a/server/.env.example +++ b/server/.env.example @@ -99,3 +99,12 @@ VECTOR_DB="lancedb" #PASSWORDNUMERIC=1 #PASSWORDSYMBOL=1 #PASSWORDREQUIREMENTS=4 + +########################################### +######## ENABLE HTTPS SERVER ############## +########################################### +# By enabling this and providing the path/filename for the key and cert, +# the server will use HTTPS instead of HTTP. +#ENABLE_HTTPS="true" +#HTTPS_CERT_PATH="sslcert/cert.pem" +#HTTPS_KEY_PATH="sslcert/key.pem" diff --git a/server/index.js b/server/index.js index 1a106053c..d8d3eabb6 100644 --- a/server/index.js +++ b/server/index.js @@ -15,10 +15,9 @@ const { getVectorDbClass } = require("./utils/helpers"); const { adminEndpoints } = require("./endpoints/admin"); const { inviteEndpoints } = require("./endpoints/invite"); const { utilEndpoints } = require("./endpoints/utils"); -const { Telemetry } = require("./models/telemetry"); const { developerEndpoints } = require("./endpoints/api"); -const setupTelemetry = require("./utils/telemetry"); const { extensionEndpoints } = require("./endpoints/extensions"); +const { bootHTTP, bootSSL } = require("./utils/boot"); const app = express(); const apiRouter = express.Router(); const FILE_LIMIT = "3GB"; @@ -95,20 +94,8 @@ app.all("*", function (_, response) { response.sendStatus(404); }); -app - .listen(process.env.SERVER_PORT || 3001, async () => { - await setupTelemetry(); - console.log( - `Primary server listening on port ${process.env.SERVER_PORT || 3001}` - ); - }) - .on("error", function (err) { - process.once("SIGUSR2", function () { - Telemetry.flush(); - process.kill(process.pid, "SIGUSR2"); - }); - process.on("SIGINT", function () { - Telemetry.flush(); - process.kill(process.pid, "SIGINT"); - }); - }); +if (!!process.env.ENABLE_HTTPS) { + bootSSL(app, process.env.SERVER_PORT || 3001); +} else { + bootHTTP(app, process.env.SERVER_PORT || 3001); +} diff --git a/server/utils/boot/index.js b/server/utils/boot/index.js new file mode 100644 index 000000000..7134198e7 --- /dev/null +++ b/server/utils/boot/index.js @@ -0,0 +1,63 @@ +const { Telemetry } = require("../../models/telemetry"); +const setupTelemetry = require("../telemetry"); + +function bootSSL(app, port = 3001) { + try { + console.log( + `\x1b[33m[SSL BOOT ENABLED]\x1b[0m Loading the certificate and key for HTTPS mode...` + ); + const fs = require("fs"); + const https = require("https"); + const privateKey = fs.readFileSync(process.env.HTTPS_KEY_PATH); + const certificate = fs.readFileSync(process.env.HTTPS_CERT_PATH); + const credentials = { key: privateKey, cert: certificate }; + + https + .createServer(credentials, app) + .listen(port, async () => { + await setupTelemetry(); + console.log(`Primary server in HTTPS mode listening on port ${port}`); + }) + .on("error", catchSigTerms); + return app; + } catch (e) { + console.error( + `\x1b[31m[SSL BOOT FAILED]\x1b[0m ${e.message} - falling back to HTTP boot.`, + { + ENABLE_HTTPS: process.env.ENABLE_HTTPS, + HTTPS_KEY_PATH: process.env.HTTPS_KEY_PATH, + HTTPS_CERT_PATH: process.env.HTTPS_CERT_PATH, + stacktrace: e.stack, + } + ); + return bootHTTP(app, port); + } +} + +function bootHTTP(app, port = 3001) { + if (!app) throw new Error('No "app" defined - crashing!'); + + app + .listen(port, async () => { + await setupTelemetry(); + console.log(`Primary server in HTTP mode listening on port ${port}`); + }) + .on("error", catchSigTerms); + return app; +} + +function catchSigTerms() { + process.once("SIGUSR2", function () { + Telemetry.flush(); + process.kill(process.pid, "SIGUSR2"); + }); + process.on("SIGINT", function () { + Telemetry.flush(); + process.kill(process.pid, "SIGINT"); + }); +} + +module.exports = { + bootHTTP, + bootSSL, +};