Setting up a ec2 instance on AWS for web real time communication platform over nodejs and socket.io using WebRTC.
Primarily a Web Call , Chat and conference platform uses WebRTC for the media stream and socketio for the signalling . Additionally used technologies are nosql for session information storage , REST Apis for getting sessions details to third parties.
Below is a comprehensive setup if ec2 t2.micro free tier instance, installation with a webrtc project module and samples of customisation and usage .
Technologies used are listed below :
Server
- ec2 instance t2.micro covered under free tier
- domain name
- SSL certificate
Core module for Web Calling feature
- WebRTC
- Node.js
- socket.io
UI components
- javascript
- css
- html5
- bootstrap
- jquerry
Supporting setup for session management
- Code version-ing and maintenance
- git
- npm
Sample Project https://github.com/altanai/webrtcdevelopment
Amazon’s free tier ec2
Amazon EC2 : These are elastic compute general purpose storage servers that mean that they can resize the compute capacity in the cloud based on load . 750 hours per month of Linux, RHEL, or SLES t2.micro instance usage. Expires 12 months after sign-up.
Some other products are also covered under free tier which may come in handy for setting up the complete complatorm. Here is a quick summary
Amazon S3 : it is a storage server. Can be used to store media file like image s, music , videos , recorded video etc .
Amazon RDS : It a relational database server . If one is using mysql or postgress for storing session information or user profile data . It is good option .
Amazon SES : email service. Can be used to send invites and notifications to users over mail for scheduled sessions or missed calls .
Amazon CloudFront : It is a CDN ( content delivery network ) . If one wants their libraries to be widly available without any overheads . CDN is a good choice .
Alternatively any server from Google cloud , azure free tier or digital ocean or even heroku can be used for WebRTC code deployment . Note that webrtc capture now requires htps in domain name.
Server Setup
Set up environment by installing nvm , npm and git ( source version control)
1. NVM ( node version manager )
cURL:
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.1/install.sh | bash
or Wget:
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash
To check installation
command -v nvm
nvm
2. NPM( node package manager)
sudo apt-get install npm

2. Git
sudo apt-get install git

SSL certificates
Since 2015 it has become mandatory to have only https origin request WebRTC’s getUserMedia API ie Voice, video, geolocation , screen sharing require https origins.
Note that this does not apply to case where its required to only serve peer’s media Stream or using Datachannels . Voice, video, geolocation , screen sharing now require https origins
For A POC purpose here is th way of generating a self signed certificate
Transport Layer Security and/or Secure Socket Layer( TLS/SSL) is a public/private key infrastructure.Following are the steps
1.create a private key
openssl genrsa -out webrtc-key.pem 2048
2.Create a “Certificate Signing Request” (CSR) file
openssl req -new -sha256 -key webrtc-key.pem -out webrtc-csr.pem
3.Now create a self-signed certificate with the CSR,
openssl x509 -req -in webrtc-csr.pem -signkey webrtc-key.pem -out webrtc-cert.pem
However in production or actual implementation it is highly recommended to use a signed certificate by CA as For examples include
- Godaddy (https://ca.godaddy.com/web-security/ssl-certificate) ,
- Comoddo (https://ssl.comodo.com/) ,
- Global Sign (https://www.globalsign.com/en/ssl/managed-ssl/) ,
- Symantec (https://www.symantec.com/ssl-certificates) etc .
Web Server
create https certificate using self generate or purchased SSL certificates using fs , node-static and https modules . To know how to create self generated SSL certificates follow section above on SSL certificates.
var fs = require(‘fs’);
var _static = require(‘node-static’);
var https = require(‘https’);
var file = new _static.Server("./", {
cache: 3600,
gzip: true,
indexFile: "index.html"
});
var options = {
key: fs.readFileSync(‘ssl_certs/webrtc-key.pem’),
cert: fs.readFileSync(‘ssl_certs/webrtc-cert.pem’),
ca: fs.readFileSync(‘ssl_certs/webrtc-csr.pem’),
requestCert: true,
rejectUnauthorized: false
};
var app = https.createServer(options, function(request, response){
request.addListener(‘end’, function () {
file.serve(request, response);
}).resume();
});
app.listen("8080");
Web servers work with the HTTP (and HTTPS) protocol which is TCP based. As a genral rule TCP establishes connection whereas UDP send data packets
Scoketio signalling server as npm
Socket.io determines which of the following real-time communication method is suited to the particular client and its network bandwidth .
- WebSocket
- Adobe Flash Socket
- AJAX long polling
- AJAX multipart streaming
- Forever Iframe
- JSONP Polling
The socket.io server needs a HTTP Server for initial handshake. The general steps for socketio signalling server
1.require socket.io and keep the reference
var io = require(‘socket.io’)
2.Create your http / https server outline in section on webserver
3.bind your http and https servers (.listen)
io.listen(app, {
log: false,
origins: ‘*:*’
})
4. Optionally set transport
io.set(‘transports’, [
‘websocket’
])
5.setup io events
io.sockets.on(‘connection’, function (socket) {
//Do domething
})
Note that Socket.io or websockets require an http server for the initial handshake.
Install ssocketio npm module
npm install socket.io
Complete code for signalling server
const io = require("socket.io")
.listen(app, {
log: false,
origins: "*:*"
});
io.set("transports", ["websocket"])
var channels = {};
io.sockets.on("connection", function (socket) {
console.log("connection");
var initiatorChannel = "";
if (!io.isConnected) {
io.isConnected = true;
}
socket.on("namespace", function (data) {
onNewNamespace(data.channel, data.sender);
})
socket.on("new-channel", function (data) {
if (!channels[data.channel]) {
initiatorChannel = data.channel;
}
console.log("new channel", data.channel, "by", data.sender)
channels[data.channel] = {
channel: data.channel,
users: [data.sender]
};
})
socket.on("join-channel", function (data) {
console.log("Join channel", data.channel, "by", data.sender)
channels[data.channel].users.push(data.sender);
})
socket.on("presence", function (channel) {
var isChannelPresent = !!channels[channel.channel];
console.log("presence for channel ", isChannelPresent)
socket.emit("presence", isChannelPresent)
})
socket.on("disconnect", function (channel) {
// handle disconnected event
})
socket.on("admin_enquire", function (data) {
switch (data.ask) {
case "channels":
socket.emit("response_to_admin_enquire", channels)
break;
case "channel_clients":
socket.emit("response_to_admin_enquire", io.of("/" + data.channel).clients());
break;
default :
socket.emit("response_to_admin_enquire", channels)
}
})
})
function onNewNamespace(channel, sender) {
console.log("onNewNamespace", channel);
io.of("/" + channel).on("connection", function(socket) {
var username;
if (io.isConnected) {
io.isConnected = false;
socket.emit("connect", true)
}
socket.on("message", function (data) {
if (data.sender == sender) {
if(!username) username = data.data.sender;
socket.broadcast.emit("message", data.data)
}
})
socket.on("disconnect", function() {
if(username) {
socket.broadcast.emit("user-left", username)
username = null;
}
})
})
}
WebRTC main HTML5 project
This is the front end section of the whole exercise . It contains JavaScript , css and html5 to make a webrtc call
<body id="pagebody">
<div id="elementToShare" className="container-fluid">
<!-- ................................ top panel ....................... -->
<div className="row topPanelClass">
<div id="topIconHolder">
<ul id="topIconHolder_ul">
<li hidden><span id="username" className="userName" hidden>a</span></li>
<li hidden><span id="numbersofusers" className="numbers-of-users" hidden></span></li>
<li><span id="HelpButton" className="btn btn-info glyphicon glyphicon-question-sign topPanelButton"
data-toggle="modal" data-target="#helpModal"> Help </span></li>
</ul>
</div>
</div>
<!-- .............alerts................. -->
<div className="row" id="alertBox" hidden="true"></div>
<!-- .......................... Row ................................ -->
<div className="row thirdPanelClass">
<div className="col-xs-12 videoBox merge" id="videoHold">
<div className="row users-container merge" id="usersContainer">
<div className="CardClass" id="card">
<!-- when no remote -->
<div id="local" className="row" hidden="">
<video name="localVideo" autoPlay="autoplay" muted="true"/>
</div>
<!-- when remote is connected -->
<div id="remote" className="row" style="display:inline" hidden>
<div className="col-sm-6 merge" className="leftVideoClass" id="leftVideo">
<video name="video1" hidden autoPlay="autoplay" muted="true"></video>
</div>
<div className="col-sm-6 merge" className="rightVideoClass" id="rightVideo">
<video name="video2" hidden autoPlay="autoplay"></video>
</div>
</div>
</div>
</div>
</div>
</div>
<!--modal help -->
<div className="modal fade" id="helpModal" role="dialog">
<div className="modal-dialog modal-lg">
<div className="modal-content">
<div className="modal-header">
<button type="button" className="close" data-dismiss="modal">×</button>
<h4 className="modal-title">Help</h4>
</div>
<div className="modal-body">
WebRTC Runs in only https due to getusermedia security contraints
</div>
<div className="modal-footer">
<button type="button" className="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>
</body>
the document start script that invokes the JS script
$('document').ready(function () {
sessionid = init(true);
var local = {
localVideo: "localVideo",
videoClass: "",
userDisplay: false,
userMetaDisplay: false
};
var remote = {
remotearr: ["video1", "video2"],
videoClass: "",
userDisplay: false,
userMetaDisplay: false
};
webrtcdomobj = new WebRTCdom(
local, remote
);
var session = {
sessionid: sessionid,
socketAddr: "https://localhost:8084/"
};
var webrtcdevobj = new WebRTCdev(session, null, null, null);
startcall();
});
Common known issues:
1.Opening page https://<web server ip>:< web server port>/index.html says insecure
This is beacuse the self signed certificates produced by open source openSSL is not recognized by a trusted third party Certificate Agency.
A CA ( Certificate Authority ) issues digital certificate to certify the ownership of a public key for a domain.
To solve the access issue goto https://<web server ip>:< web server port> and given access permission such as outlined in snapshot below

2.Already have given permission to Web Server , page loads but yet no activity .
if you open developer console ( ctrl+shift+I on google chrome ) you will notice that there migh be access related errros in red .
If you are using different server for web server and signalling server or even if same server but different ports you need to explicity go to the signalling server url and port and give access permission for the same reason as mentione above.
3.no webcam capture on opening the page
This could happen due to many reasons
- page is not loaded on https
- browser is not webrtc compatible
- Media permission to webcam are blocked
- the machine does have any media capture devices attached
- Driver issues in the client machine while accessing webcams and mics .
4.socketio + code: 0, message: “Transport unknown”
Due to the version v1.0.x of socket.io
while performing handshake . To auto correct this , downgrade to v0.9.x
Instead of self signed certificate, it is probably preferable to use one from https://letsencrypt.org/. Associated client will automatically renew the certificate as well. It is also a recognized authority.
Hello Aswath .. sure one can use letsencrypt too …however i havent used it uptill now hence didnt write about it . I could give it a shot thanks to you and edit back here if it works for the webrtc APIs .