I am learning how to build an http2 server with NodeJS 10 LTS official documentation. I copy pasted the server side code into server.js and run node on it, but when I try to connect with postman (REST testing tool) I receive an error.
const http2 = require('http2');
const fs = require('fs');
const server = http2.createSecureServer({
key: fs.readFileSync('localhost-privkey.pem'),
cert: fs.readFileSync('localhost-cert.pem')
});
server.on('error', (err) => console.error(err));
server.on('stream', (stream, headers) => {
// stream is a Duplex
stream.respond({
'content-type': 'text/html',
':status': 200
});
stream.end('<h1>Hello World</h1>');
});
server.listen(8443);
The error I receive from postman is as follows:
Unknown ALPN Protocol, expected `h2` to be available.
If this is a HTTP request: The server was not configured with the `allowHTTP1` option or a listener for the `unknownProtocol` event.
Things I have tried to solve the problem:
As required in the official documentation I have created private and public certificate (.pem).
I have included the public certificate inside postman software. So now the only error I receive is the one mentioned above (Unknown ALPN protocol).
What else is needed to make the example in the official docs work? I could not find online resources for that, and all the previous questions on stackoverflow relates to old versions of NodeJS when http2 was not still native.
Try to add allowHTTP1: true in Server options at it says server not configure with the allowHTTP1
const server = http2.createSecureServer({
key: fs.readFileSync('localhost-privkey.pem'),
cert: fs.readFileSync('localhost-cert.pem')
});
To
const server = http2.createSecureServer({
key: fs.readFileSync('localhost-privkey.pem'),
cert: fs.readFileSync('localhost-cert.pem'),
allowHTTP1: true
});
From github http2 documentation :
allowHTTP1 {boolean} Incoming client connections that do not support HTTP/2 will be downgraded to HTTP/1.x when set to true. See the 'unknownProtocol' event. See ALPN negotiation. Default: false.
Here i found better answer already on Stackoverflow Configure HTTP2 NodeJS Server
Ok, after thorough investigation I found a satisfactory answer to a great extent.
The https request should be https://localhost:8443/stream to get a response from the server with Hello World. Without the stream path there is no response.
postman gives 403 response after installing the public certificate, but insomnia doesn't give any response.
Using google chrome developer tools in the Network tab I can finally get response 200 OK from the server as shown below.
Related
I'm going insane trying to get a super basic wss:// functioning in NodeJS for the last 2 days. I've tried quite a few methods and libraries but I can't seem to get the websocket server attached to an https instance. I have no problem leveraging regular old http and attaching it to that instance. I don't get any errors in my debug console.
I've created both self-style type certs (Create Key + CA, create CSR,
sign it, use new server cert), and (Create Key + self-signed Cert,
use them).
I've tried disabling TLS verification via env var:
NODE_TLS_REJECT_UNAUTHORIZED="0"
I've tried both ws, and websocket libraries and many different combos
of basic ws creation vs server attaching methods.
I've built a VM of Ubuntu 21.04, installed dependencies and vscode
just to rule out my OS. Same issue here.
Tried using node versions 14 + 16.
:Package Deps:
"websocket": "^1.0.34",
"ws": "^8.0.0"
:server.js:
const fs = require('fs');
const WebSocket = require('ws');
//HTTPS
const https = require('https');
const server = new https.createServer({
key: fs.readFileSync('./config/certs/key.pem'),
cert: fs.readFileSync('./config/certs/cert.pem')
});
//HTTP
// const http = require('http');
// const server = new http.createServer();
const wss = new WebSocket.Server({server});
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
console.log('received: %s', message);
ws.send('hello from server!, the time is: ' + timestamp());
});
});
//Helper function to create a timestamp
function timestamp() {
return (new Date)
.toISOString()
.replace(/z|t/gi, ' ')
.trim()
};
//Start the server
server.listen(3000);
I'm suspecting some underlying compatibility issues between node and dependencies or something...Any advice would be much appreciated. I'm not too familiar with debugging internal modules so if there are some command line switches I should add to node/nodemon please let me know. I have --inspect and --trace-warnings enabled at the very least.
I just figured it out and as usual it was something simple and overlooked. I've been using Firefox with the Weasel client add-on to test websockets. I had imported my self-signed cert along with the root CA cert I had created into Firefox. Even though it was imported, I still had to navigate to the HTTPS url and acknowledge the wonderful yellow border popup. As soon as I clicked on "Accept risk and continue" I tabbed over to Weasel and it established a connection to wss://localhost:3000 with no problems.
Even though the cert is whitelisted I still receive the warning page and have to acknowledge it. Next time I'll try a different client like one built in another language (Python, .NET...). Never would have thought it to be a browser issue but it makes sense with the way ssl/tls works.
I've got an HTTPS webpage that won't let me connect to an insecure websocket, which I was using to communicate with a node sever, so I'm trying to migrate my node server to https. The client-side https page was given to me to integrate my previously insecure page with, so I don't know anything about the certs it's using, if that matters.
To connect to it, on the client side I was using connection = new Websocket('ws://node_server_address') which worked fine for insecure connections. Now that the page uses https, I'm just using connection = new Websocket('wss://node_server_address'), which I hope is all I need to change on the client side. However, with self signed certs on the node server, I get this error when I try to connect with Chrome:
Websocket connection to 'wss://address' failed: Error in connection establishment: net::ERR_CERT_AUTHORITY_INVALID
On Firefox all it tells me is that it can't connect to the server. I've seen plenty of examples where they don't specify a CA at all and they supposedly work fine, so I'm hoping I don't have to mess with that. However, assuming the only solution is to specify some valid CA, how would I generate that for a self-signed certificate?
Node server:
const https = require('https');
const WebSocketServer = require('websocket').server;
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
let serverOptions = {
key: fs.readFileSync("./self-signed.key"),
cert: fs.readFileSync("./self-signed.cert"),
requestCert: false,
rejectUnauthorized: false
}
const server = https.createServer(serverOptions, (req, res) => { res.end('') });
server.listen(port, function() { /* Logging */ }
const wsServer = new WebSocketServer({
httpServer:server
});
So I'm trying to get a basic https server running in node, and I'm completely stuck. I've generated a self signed certificate and key with openssl, and tried the basic way to create the server and another hundred of them, but no matter what I do my browser just tells me "The connection has been reset" when I try to connect, and the server doesn't even execute the callback function for the request, as if it has never arrived.
The network inspector in Firefox Developer Edition shows no response at all from the server, and inspecting my loopback interface using Wireshark I've found the server is sending an "end" package right after acknowledging the browser's request.
I really have no idea on what can be wrong, as I've tried with example codes from many tutorials and all of them produce the same output.
This is an example of some very basic code that throws no errors, but also apparently doesn't work:
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('sslcert/key.pem'),
cert: fs.readFileSync('sslcert/server.crt'),
rejectUnauthorized: false
}
https.createServer(options, (req, res) => {
console.log('request received')
res.writeHead(200)
res.end('hello')
}).listen(8443).on('error', (error) => {
throw error
})
I had the same problem, and for me, accessing the page with the https:// -protocol specified did the job in Firefox.
So use
https://localhost:8443
instead of just
http://localhost:8443
I'm trying to create a HTTPS proxy server in Node.JS v0.10.24 using a self-signed certificate. Here's the code I'm using:
var https = require('https');
var server = https.createServer({
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem')
});
server.on('request', function(req, res) {
res.end('hello');
});
server.listen(8080);
This server correctly boots up and is accessible via https://localhost:8080. However, when I set it as a HTTPS proxy (on Mac OS X), the server emits connection events but never emits either request or error, thus causing the connection to hang indefinitely and eventually time out.
I encountered the same issue on my Macbook. The issue appears to be that the proxy server option in OSX is using the HTTP CONNECT method to tunnel HTTPS requests.
In short, this means that you need make your server a http.Server instance and handle the connect event, which will involve forwarding TCP socket traffic.
I know this reply is a bit late, but I wrote my own HTTP/S proxy server that you can look at for reference: https://github.com/robu3/purokishi. The specific section covering the connect method is here.
I'm trying to write a reverse proxy in node.js using express, and it works fine for http requests. The problem is that when requesting https it never responds, and the browser states that the proxy refused to connect.
Here is the working code for http requests:
var app = express(),
http=require('http');
app.configure(function(){ /* express stuff to log and use routes and the like */ });
http.createServer(app).listen(8000, function(){
console.log("Express server listening on port " + 8000);
});
app.all('*', proxy);
var request=require('request');
var proxy=function(req,resp){
var data={
url:req.url,
headers: {
'Connection': 'keep-alive'
}
}
var proxy=request(req.url);
proxy.pipe(resp);
}
Now, as for SSL, i am currently trying with:
var https=require('https'),
fs=require('fs');
https.createServer({
key: fs.readFileSync(__dirname+'/ssl/server.key', 'utf8'),
cert: fs.readFileSync(__dirname+'/ssl/server.crt', 'utf8')
},app).listen(8001, function(){
console.log("Express server listening on port " + 8001);
});
The proxy can be used from anywhere requiring 50.56.195.215:8000 for HTTP and 50.56.195.215:8001 for SSL. It has no security whasoever, so don't log in to anything important =D
I'm using a self signed SSL Certificate, and i guess it's kind of silly of me to try to do such a thing, but i don't have any ideas left :P
My suggestion is use the great existing library node-http-proxy from Nodejitsu. If you want to write your own, at least study their source code academically.
Some notes on your approach above:
You aren't handling HTTP methods other than GET (POST, PUT, DELETE, etc). These exist. You must handle them if you want your proxy to actually work. Every time you call request(req.url), request is making a GET request by default.
For HTTPS, you need to be able to handle HTTP Connects and also impersonate the destination server. You will need to have a Certificate for this.
You can try using this.
https://github.com/noeltimothy/noelsproxy
Copy the directory "magical" that contains a certificate as well as a key and then use noelsproxy. Remember to add the ca.pem to your trusted root store on your system.
If you are using windows, do this:
certutil -addstore -enterprise -f \"Root\" ./magical/ca.pem
Let me know if you have any issues. I'm willing to fix them immediately.