Auto update ssl node.js - javascript

is there any way to make the node.js server update automatically with the new certificates generated by let's encrypt every 3 months without restarting the service?
My server has a hosting panel that auto manages the certificates, so I can't use the certbot manually.
Currently I have a cron that runs monthly and restarts the server to take the new changes, but sometimes the certificate changes a few days before and my sites and apis stop working until my server restarts. It doesn't seem to me the most optimal solution.
const fs = require("fs");
const https = require("https");
const express = require("express");
const helmet = require("helmet");
var cors = require("cors");
const API = require("./index.js");
const hostname = "ENV.HOSTAME";
const httpsPort = ENV.PORT;
const httpsOptions = {
cert: fs.readFileSync("CERT-PATH"),
ca: fs.readFileSync("CA-PATH"),
key: fs.readFileSync("CA-KEY"),
};
const app = express();
app.use(helmet());
app.use(cors());
const httpsServer = https.createServer(httpsOptions, app);
// Parse URL-encoded bodies (as sent by HTML forms)
//app.use(express.urlencoded());
// Parse JSON bodies (as sent by API clients)
app.use(express.json());
app.get("/", function (req, res) {
res.redirect("HOSTNAME");
});
app.post("API-ROUTE", async function (req, res) {
const response = await API(req);
if (response != "Error") {
res.status(200).send(response);
} else {
res.status(500).json({ message: "Server Error" });
}
});
httpsServer.listen(httpsPort, hostname);

nodejs uses http service and nginx for reverse proxy. When the certificate is updated, there is no need to restart the whole service. Executing nginx -s reload works for me.

Related

Unable to setup Express server on HTTPS

Trying to set up my Express server on HTTPS but unable to access my api. Here is my code:
// server.js
const express = require('express');
const { readFileSync } = require('fs');
const https = require('https');
const app = express();
const key = readFileSync(
'/etc/letsencrypt/live/mydomain.com/privkey.pem',
'utf8'
);
const cert = readFileSync(
'/etc/letsencrypt/live/mydomain.com/fullchain.pem',
'utf8'
);
const ca = readFileSync(
'/etc/letsencrypt/live/mydomain.com/chain.pem',
'utf8'
);
const credentials = { key, cert, ca };
const port = 443
const server = https.createServer(credentials, app);
server.listen(port, () => console.log(`Server is running on port ${port}`));
The error I am receiving is a 502 Bad gateway on all calls to the server.
Everything worked perfectly before when I was running on HTTP like this:
const server = app.listen(8000, () => {});
Beside the URL on my site I can see the padlock icon and it says my site is secure so I believe my certifcate is valid.
Have seen a lot of similar questions posted on here and followed what I've seen in responses. I've even asked chatGPT to check my code and it doesn't see any errors. I've also tried reading my SSL keys as .env variables so I don't think the issue is an incorrect file path.
Can anybody please help me find the solution?
EDIT
Here is an example of a get request I am making to my backend using axios:
const fetchMembers = async () => {
await axios
.get(`/api/total-users`)
};
This invokes a function totalUsers with express.Router from a users file in my routes folder on the backend:
// routes/users.js
const express = require('express');
const router = express.Router();
router.get('/total-users', totalUsers);
const totalUsers = async (req, res) => {
try {
const total = await User.find().estimatedDocumentCount();
res.json(total);
} catch (err) {
console.log(err);
}
};
I am using a middleware app.use with a prefix /api and importing the users file to make a connection to my endpoints:
// server.js
const userRoutes = require('./routes/users')
app.use('/api', userRoutes)
While editing this question I tried modifying the middleware prefix to `:443/api' however this still hasn't helped.
Where is User defined inside of routes/users.js? You need to import your DB models before accessing them like this:
const total = await User.find().estimatedDocumentCount();
Otherwise, generally when running fetch('/api...), React will try to access localhost:3000/api instead of localhost:443/api.
React needs to know where to proxy requests to the backend. One way is using the http-proxy-middleware library and by defining a setupProxy.js file.
client/src/setupProxy.js
/**
* Proxy most calls to the server
* #type {Array}
*/
/* eslint-disable #typescript-eslint/no-var-requires */
const { createProxyMiddleware } = require('http-proxy-middleware');
const proxy_urls = ['/api/*';
const target = 'https://localhost:443';
module.exports = function (app) {
proxy_urls.forEach((url) => {
app.use(url, createProxyMiddleware({ target }));
});
};

I want to build my own webhook dispatch server using node js?

I am trying to build a webhook server using node js. If any user sets their server URL as a hook using API provided by me, then my webhook server should respond to that user server.
I got this idea from the Facebook Messenger Chatbot application which uses the same approach.
Server 1 - My Server
const express = require("express");
const axios = require("axios");
const app = express();
const PORT = 3000;
/* Set Middleware to Express App */
app.use(express.json());
// Routes
app.post("/handle-webhooks", (req, res) => {
const body = {"id": "1", "message": "hello"};
const headers = {
'Content-Type': "application/json",
}
const clientWebhookUrl = "http://localhost:8093/webhook2" // This will be different for each client
axios.post(clientWebhookUrl, body, {headers})
return res.sendStatus(200);
})
app.post("/set-webhook", (req,res) => {
const clientWebhookUrl = req.url;
// This URL will be saved to database
return res.sendStatus(200)
}
/* Listen Server */
app.listen(PORT, () => {
console.log(`App is listening on port ${PORT}.`);
})
Server 2 - My Client 1 Server
Using postman, the Client will make a post request to http://localhost:3000/set-webhook and set the webhook2 endpoint of his web server as a webhook URL to receive a response from my server.
const express = require("express");
const axios = require("axios");
const app = express();
const PORT = 8093;
/* Set Middleware to Express App */
app.use(express.json());
// Routes
app.post("/webhook2", (req, res) => {
const body = req.body; // receives {"id": "1", "message": "hello"}
return res.status(200).send(body);
})
/* Listen Server */
app.listen(PORT, () => {
console.log(`App is listening on port ${PORT}.`);
})
Is the above approach is correct for doing this task? or do I need to add more complex code for this?
Thanks.

Is this Express + HTTPS spdy + socket.io server correctly initialized?

I've been working on a project a while and I'm not sure that my https is correctly mounted since I'm not fully aware of the sentences that are invoked in the code, could someone bring some light into this?
const express = require('express')
const spdy = require('spdy')
const cors = require('cors')
const fs = require('fs')
const app = express()
const serverCertificates = {
key: fs.readFileSync(__dirname + '/cfg/cert/localhost-private.pem'),
cert: fs.readFileSync(__dirname + '/cfg/cert/localhost-cert.pem')
}
const corsOptions = {
cors: {
origin: "https://localhost:3200",
transports: ['websocket'],
upgrade: false
}
}
Up to here is just require, mounting express on app and declaring some server options
After the classic app.use statements comes the trouble, I need to run HTTPS and Socket.io in the same server, and the only role that express is doing is serving statics directories
app.use(express.json())
app.use(cors())
app.use('/', express.static('./public'))
app.get('/favico.ico', (req, res) => res.sendFile(__dirname + '/public/favico.ico'))
let server = spdy.createServer(serverCertificates, app)
let io = app.io = require('socket.io')(server, corsOptions)
io.attach(server)
server.listen(3200, (error) => {
if (error) {
return process.exit(1)
} else {
console.log('Escuchando en *:' + PORT)
}
})
server.on('error', err => console.log(err))
Now I'm not using express routing as an API because the communication with client is done by Express.IO but eventually the project must contain a database that would be handled by express.
The question is "am I doing the right things here? is there a better way of mounting this type of server?"
Thanks in advance

Respond to client after receiving client to server POST request (Node.JS)

I have been attempting to respond to a client-side request with Node.JS. I have discovered Node JS - call function on server from client javascript, which seems to explain what I want, except that I can't seem to translate it to my program.
Here is the request via POST in index.html:
$.post("/", {data: 'hi'}, function(result){
$("body").html(result);
});
what I was hoping it would do would be write the result of the call, from my server.js (Node):
const express = require('express');
const path = require('path');
const http = require('http');
const fs = require('fs');
function handler(data, app){
if(req.method == "POST"){
app.setHeader('Content-Type', 'text/html');
app.writeHead(200);
app.end(data);
}
}
const BUILDPATH = path.join(__dirname);
const { PORT = 3000 } = process.env;
const app = express();
app.set('port', PORT);
app.use(express.static(BUILDPATH));
app.get('/*', (req, res) => res.sendFile('static/index.html', { root: BUILDPATH }));
const httpServer = http.createServer(app);
httpServer.listen(PORT);
console.info(`🚀 Client Running on: http://localhost:${PORT}`);
try this code:
const express = require('express');
const path = require('path');
const http = require('http');
const fs = require('fs');
function handler(data, app){
if(req.method == "POST"){
app.setHeader('Content-Type', 'text/html');
app.writeHead(200);
app.end(data);
}
}
const BUILDPATH = path.join(__dirname);
const { PORT = 3000 } = process.env;
const app = express();
app.set('port', PORT);
app.use(express.static(BUILDPATH));
app.get('/', (req, res) => {
res
// best practice is to always return an status code
.status(200)
// just return an json object
.json({"msg": "ok, it all works just fine"})
});
const httpServer = http.createServer(app);
httpServer.listen(PORT);
console.info(`🚀 Client Running on: http://localhost:${PORT}`);
The issue is, is that the only route your Node server listens to is the one you define with /*. As you can see, that route returns your index.html file to the client. You did not specify a route that listens for a request that comes from the client.
To solve the issue, you will have to define a route that listens on a specific route for the request you are trying to make from your client.
I see you are using ExpressJS. here is the documentation on writing routes.

Continuously changing Express Route Paths for protection

I want to create a hidden internal webserver with ever-changing routes.
The aim is to prevent/deter people from scraping the site or using the API without permission.
There's probably a better way (or this could be totally useless)
I've written some code that works but either convince me why I'm wasting my time or why it would work.
const express = require('express');
const uuid = require('uuid/v4');
const app = express();
// These are the hidden routes
const routes = {
hiddenPage: undefined,
};
setInterval(() => {
// Change the path of the hidden page
// every 5 seconds
routes.hiddenPage = `/${uuid()}`;
}, 1000 * 5);
app.get('*', (req, res) => {
// There would be other middleware for
// security reasons
if (req.path === routes.hiddenPage) {
res.send('Welcome to the hidden page');
return;
}
res.send(`Page at <a href=${routes.hiddenPage}>${routes.hiddenPage}</a>`);
});
// Listen on 3000
app.listen(3000);
You can use CORS middleware to allow only specific clients to access your server.
https://expressjs.com/en/resources/middleware/cors.html
Example:
var express = require('express')
var cors = require('cors')
var app = express()
var corsOptions = {
origin: 'http://example.com',
}
app.get('/products/:id', cors(corsOptions), function (req, res, next) {
res.json({msg: 'This is CORS-enabled for only example.com.'})
})
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})

Categories