EPROTO Error when connecting to a server using https
Environment
- Platform:
$ uname -a
Linux vote 5.4.0-26-generic #30-Ubuntu SMP Mon Apr 20 16:58:30 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
- Docker Version:
$ docker --version
Docker version 20.10.7, build 20.10.7-0ubuntu5~20.04.2
- Node.js Version:
node --version
v10.19.0
-
Image Tag: I tested all
node:alpine,node:stretch,node:slimandnode:17
Expected Behavior
I developed a Node.js program which works fine on my system but behaves strange inside docker container! In this program I'm trying to connect to a server using https. On my system It always connects successfully but inside docker container it just can connect first time and then exits with error.
NOTE: Inside docker container, If it was never connecting then it made sense but now it's really strange that it can connect one time but not more.
The expected output should looks like to what I see on my system:
$ npm run development
> [email protected] development /home/sysadmin/test
> export NODE_ENV=development; export DEBUG=app:*; node server.js
app::main-Interface Server started listening on port : 8086 +0ms
app::main-Interface Data received! +5s
app::main-Interface First operation succeed +3ms
app::main-Interface Data received! +6s
app::main-Interface First operation succeed +1ms
app::main-Interface Data received! +11s
app::main-Interface First operation succeed +0ms
^C
As you can see it connects to the server three times without any problem and works fine.
Current Behavior
It just connects one time and then it throws an error:
> [email protected] development
> export NODE_ENV=development; export DEBUG=app:*; node server.js
2022-02-26T05:58:48.550Z app::main-Interface Server started listening on port : 3000
2022-02-26T05:58:49.818Z app::main-Interface Data received!
2022-02-26T05:58:49.824Z app::main-Interface First operation succeed
node:events:498
throw er; // Unhandled 'error' event
^
Error: write EPROTO 80B9D562707F0000:error:0A000152:SSL routines:final_renegotiate:unsafe legacy renegotiation disabled:../deps/openssl/openssl/ssl/statem/extensions.c:907:
at WriteWrap.onWriteComplete [as oncomplete] (node:internal/stream_base_commons:94:16)
Emitted 'error' event on ClientRequest instance at:
at TLSSocket.socketErrorListener (node:_http_client:442:9)
at TLSSocket.emit (node:events:520:28)
at emitErrorNT (node:internal/streams/destroy:164:8)
at emitErrorCloseNT (node:internal/streams/destroy:129:3)
at processTicksAndRejections (node:internal/process/task_queues:83:21) {
errno: -71,
code: 'EPROTO',
syscall: 'write'
}
Node.js v17.4.0
Steps to Reproduce
I simplified the code as below(content of server.js):
const express = require('express');
const debug = require('debug');
const https = require('https')
const log = debug('app::main-Interface');
const args = process.argv.slice(2);
const app = express();
const port = args[0] || process.env.port || 3000;
function sleep(toSleep){
return new Promise((resolve, reject)=>{
setTimeout(() => {
resolve(true)
}, toSleep);
})
}
async function initializeRemotely(lengthOfOrder = 4096){
return new Promise((resolve, reject)=>{
https.get(`https://2ton.com.au/getprimes/random/${lengthOfOrder}`,
(res)=>{
res.on('data', async (data)=>{
log('Data received!')
resolve(true);
})
}
)
})
}
async function DEBUG(){
let breakTime = 5000;
while(true){
await initializeRemotely()
log('First operation succeed')
await sleep(breakTime);
breakTime *= 2;
}
}
app.listen(port, async () => {
log(`Server started listening on port : ${port}`);
//schedulerPool.MSRulesWatcher(config.get('Times.schedulers'));
DEBUG()
});
To run this program you need to install following packages:
npm i debug express
After installing those, you can run the program as below to see Expected Behavior:
$ DEBUG=app::* node server.js
Then create the ./deploy/Dockerfile as below:
FROM node:alpine
EXPOSE 3000
WORKDIR /interface
COPY package.json .
RUN npm install
COPY . .
And also create the docker-compose.yml file with following contents:
version: "3"
services:
interface:
image: interface
container_name: interface
build:
context: .
dockerfile: ./deploy/Dockerfile
entrypoint: ["npm", "run", "development"]
Also the development script inside package.json file is:
...
"scripts": {
"development": "export NODE_ENV=development; export DEBUG=app:*; node server.js"
},
...
Now to reproduce error, just build and run the container:
$ sudo docker-compose build
Building interface
Step 1/6 : FROM node:alpine
---> 025c3cbb849f
Step 2/6 : EXPOSE 3000
---> Using cache
---> 01c2a8f41688
Step 3/6 : WORKDIR /interface
---> Using cache
---> a8323f19dd04
Step 4/6 : COPY package.json .
---> Using cache
---> bccbb39147bd
Step 5/6 : RUN npm install
---> Using cache
---> 573aa7b45092
Step 6/6 : COPY . .
---> Using cache
---> a2f41c692811
Successfully built a2f41c692811
Successfully tagged interface:latest
$ sudo docker-compose up -d
Starting interface ... done
Finally if you look at logs, you can see the problem:
$ sudo docker logs interface
> [email protected] development
> export NODE_ENV=development; export DEBUG=app:*; node server.js
2022-02-26T05:58:48.550Z app::main-Interface Server started listening on port : 3000
2022-02-26T05:58:49.818Z app::main-Interface Data received!
2022-02-26T05:58:49.824Z app::main-Interface First operation succeed
node:events:498
throw er; // Unhandled 'error' event
^
Error: write EPROTO 80B9D562707F0000:error:0A000152:SSL routines:final_renegotiate:unsafe legacy renegotiation disabled:../deps/openssl/openssl/ssl/statem/extensions.c:907:
at WriteWrap.onWriteComplete [as oncomplete] (node:internal/stream_base_commons:94:16)
Emitted 'error' event on ClientRequest instance at:
at TLSSocket.socketErrorListener (node:_http_client:442:9)
at TLSSocket.emit (node:events:520:28)
at emitErrorNT (node:internal/streams/destroy:164:8)
at emitErrorCloseNT (node:internal/streams/destroy:129:3)
at processTicksAndRejections (node:internal/process/task_queues:83:21) {
errno: -71,
code: 'EPROTO',
syscall: 'write'
}
Node.js v17.4.0