diff --git a/docs/env.md b/docs/env.md index 9f13692b6..d41537390 100644 --- a/docs/env.md +++ b/docs/env.md @@ -63,8 +63,9 @@ Environmental variables are also tracked in `ENVIRONMENT_VARIABLES` within `src/ - `UNSAFE_URLS`: Array or regular expression URLs to be excluded from access.Example: ["^.*(169.254.169.254).*","^.*(127.0.0.1).*"] ## HTTP - - `HTTP_API_PORT`: Port number for the HTTP API. Example: `8000` +- `HTTP_CERT_PATH`: Absolute path to the TLS certificate file. If provided along with `HTTP_KEY_PATH`, the node will start an HTTPS server. Example: `"/etc/letsencrypt/live/example.com/fullchain.pem"` +- `HTTP_KEY_PATH`: Absolute path to the TLS private key file. If provided along with `HTTP_CERT_PATH`, the node will start an HTTPS server. Example: `"/etc/letsencrypt/live/example.com/privkey.pem"` ## P2P diff --git a/scripts/ocean-node-quickstart.sh b/scripts/ocean-node-quickstart.sh index 4a1ed9c97..ef663d560 100755 --- a/scripts/ocean-node-quickstart.sh +++ b/scripts/ocean-node-quickstart.sh @@ -139,6 +139,17 @@ else echo "Running node without docker C2D capabilities!" fi +read -p "Do you want to enable TLS (HTTPS) for your Ocean Node [ y/n ]: " enable_tls +if [ "$enable_tls" == "y" ]; then + read -p "Enter the absolute path to your TLS certificate file: " HTTP_CERT_PATH + read -p "Enter the absolute path to your TLS private key file: " HTTP_KEY_PATH + + if [ -z "$HTTP_CERT_PATH" ] || [ -z "$HTTP_KEY_PATH" ]; then + echo "Certificate and key paths are mandatory for TLS. Disabling TLS." + enable_tls="n" + fi +fi + # Set default compute environments if not already defined if [ -z "$DOCKER_COMPUTE_ENVIRONMENTS" ]; then echo "Setting default DOCKER_COMPUTE_ENVIRONMENTS configuration" @@ -212,12 +223,24 @@ services: # P2P_BOOTSTRAP_NODES: '' # P2P_FILTER_ANNOUNCED_ADDRESSES: '' DOCKER_COMPUTE_ENVIRONMENTS: '$DOCKER_COMPUTE_ENVIRONMENTS' +$( + if [ "$enable_tls" == "y" ]; then + echo " HTTP_CERT_PATH: '/usr/src/app/certs/cert.pem'" + echo " HTTP_KEY_PATH: '/usr/src/app/certs/key.pem'" + fi +) networks: - ocean_network volumes: - node-sqlite:/usr/src/app/databases - /var/run/docker.sock:/var/run/docker.sock +$( + if [ "$enable_tls" == "y" ]; then + echo " - $HTTP_CERT_PATH:/usr/src/app/certs/cert.pem:ro" + echo " - $HTTP_KEY_PATH:/usr/src/app/certs/key.pem:ro" + fi +) depends_on: - typesense diff --git a/src/@types/OceanNode.ts b/src/@types/OceanNode.ts index 1f43ece68..08db7b98b 100644 --- a/src/@types/OceanNode.ts +++ b/src/@types/OceanNode.ts @@ -117,6 +117,8 @@ export interface OceanNodeConfig { isBootstrap?: boolean validateUnsignedDDO?: boolean jwtSecret?: string + httpCertPath?: string + httpKeyPath?: string } export interface P2PStatusResponse { diff --git a/src/index.ts b/src/index.ts index 5eeb52366..ba2a094a9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,6 +13,7 @@ import { import { GENERIC_EMOJIS, LOG_LEVELS_STR } from './utils/logging/Logger.js' import fs from 'fs' +import https from 'https' import { OCEAN_NODE_LOGGER } from './utils/logging/common.js' import path from 'path' import { fileURLToPath } from 'url' @@ -176,9 +177,27 @@ if (config.hasHttp) { app.use(removeExtraSlashes) app.use('/', httpRoutes) - app.listen(config.httpPort, () => { - OCEAN_NODE_LOGGER.logMessage(`HTTP port: ${config.httpPort}`, true) - }) + if (config.httpCertPath && config.httpKeyPath) { + try { + const options = { + cert: fs.readFileSync(config.httpCertPath), + key: fs.readFileSync(config.httpKeyPath) + } + https.createServer(options, app).listen(config.httpPort, () => { + OCEAN_NODE_LOGGER.logMessage(`HTTPS port: ${config.httpPort}`, true) + }) + } catch (err) { + OCEAN_NODE_LOGGER.error(`Error starting HTTPS server: ${err.message}`) + OCEAN_NODE_LOGGER.logMessage(`Falling back to HTTP`, true) + app.listen(config.httpPort, () => { + OCEAN_NODE_LOGGER.logMessage(`HTTP port: ${config.httpPort}`, true) + }) + } + } else { + app.listen(config.httpPort, () => { + OCEAN_NODE_LOGGER.logMessage(`HTTP port: ${config.httpPort}`, true) + }) + } // Call the function to schedule the cron job to delete old logs scheduleCronJobs(oceanNode) diff --git a/src/utils/config/constants.ts b/src/utils/config/constants.ts index 54287345b..f3b43c244 100644 --- a/src/utils/config/constants.ts +++ b/src/utils/config/constants.ts @@ -65,7 +65,9 @@ export const ENV_TO_CONFIG_MAPPING = { P2P_AUTODIALCONCURRENCY: 'p2pConfig.autoDialConcurrency', P2P_MAXPEERADDRSTODIAL: 'p2pConfig.maxPeerAddrsToDial', P2P_AUTODIALINTERVAL: 'p2pConfig.autoDialInterval', - P2P_ENABLE_NETWORK_STATS: 'p2pConfig.enableNetworkStats' + P2P_ENABLE_NETWORK_STATS: 'p2pConfig.enableNetworkStats', + HTTP_CERT_PATH: 'httpCertPath', + HTTP_KEY_PATH: 'httpKeyPath' } as const // Configuration defaults diff --git a/src/utils/config/schemas.ts b/src/utils/config/schemas.ts index e3cf3b802..a81bd26ce 100644 --- a/src/utils/config/schemas.ts +++ b/src/utils/config/schemas.ts @@ -322,7 +322,9 @@ export const OceanNodeConfigSchema = z .default([...DEFAULT_UNSAFE_URLS]), isBootstrap: booleanFromString.optional().default(false), validateUnsignedDDO: booleanFromString.optional().default(true), - jwtSecret: z.string() + jwtSecret: z.string(), + httpCertPath: z.string().optional(), + httpKeyPath: z.string().optional() }) .passthrough() .superRefine((data, ctx) => { diff --git a/src/utils/constants.ts b/src/utils/constants.ts index a3717ff68..4f4012761 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -504,6 +504,16 @@ export const ENVIRONMENT_VARIABLES: Record = { name: 'P2P_MAX_CONNECTIONS', value: process.env.P2P_MAX_CONNECTIONS, required: false + }, + HTTP_CERT_PATH: { + name: 'HTTP_CERT_PATH', + value: process.env.HTTP_CERT_PATH, + required: false + }, + HTTP_KEY_PATH: { + name: 'HTTP_KEY_PATH', + value: process.env.HTTP_KEY_PATH, + required: false } } export const CONNECTION_HISTORY_DELETE_THRESHOLD = 300