Get in touch

Awesome Image Awesome Image

Java Developers March 26, 2024

Spring Boot for WebRTC Signaling Servers: A Comprehensive Guide

Writen by Mahipalsinh Rana


Spring Boot for WebRTC Signaling Servers_ A Comprehensive Guide - 850_350

In brief, Spring Boot is a rigorous tool that provides the developer with the required platform to develop apps of the size and complexity required. In particular, it has hit the nail on The Head for the people who code their projects in Java. All that you need when you enter WebRTC is to discard any extra software or local downloads because it allows you to share files or talk online right away, namely to make video calls or talk without the downloading of any extra software. While web-based real-time communication can be seamlessly realized, under the hood there is a signaling server, which needs to be deployed.

This server enables work well provided the devices are connected and can talk with one another properly. The detailed guide covers ways of using Spring Boot for facilitating and Simple for the WebRTC apps.

It does quite a lot as Spring Boot is already simple to use and WebRTC can conveniently handle events taking place in real time. As a result, it can be easy for developers to create applications that work on both ended meetings or live broadcasts. If your project should be built upon multiple parts that need fast and live channels through which data should be shared, this guide through instructions about setting up a strong signaling server with the Spring Boot will show you how to accomplish that.

What is WebRTC (Web Real-Time Communications)?

WebRTC stands for Web Real-Time Communication.

It is an open-source project that enables real-time communication directly between web browsers or mobile applications without the need for any plugins or additional software installations.

WebRTC provides a set of APIs and protocols that allow developers to incorporate features like voice calling, video chat, and peer-to-peer file sharing into their web applications.


How WebRTC Works?

  • WebRTC (Web Real-Time Communication) is a technology that lets you share video, audio, and general data between browsers in real-time, without needing any extra plugins or software. Here’s a simplified explanation of how it works to establish a connection between two parties, let’s call them A and B:
  • First, A looks for all the possible ways it can connect to B over the internet. These could include direct connections if they’re on the same network, or more complex routes involving relay servers if they’re on different networks or behind firewalls. B does the same on its end. This process is part of what’s known as ICE (Interactive Connectivity Establishment).
  • Once A has figured out its possible connection paths, it creates an “offer.” This offer includes information about A’s connection capabilities, such as supported audio/video formats and how it can be reached (the paths found in step 1).
  • A then sends this offer to B through a signaling server. The signaling server doesn’t process this information; it just passes messages between A and B because they can’t directly communicate yet.
  • On receiving the offer, B generates an “answer.” This answer also includes B’s connection capabilities and its preferred way of communicating based on the offer from A.
  • B sends its answer back to A through the signaling server, completing the information exchange.
  • With both the offer and answer exchanged, A and B now know how to connect with each other directly. They use the information shared to establish a peer-to-peer connection. This connection allows them to start the real-time exchange of audio, video, or data.

What is STUN, TURN, and ICE?

STUN (Session Traversal Utilities for NAT)

  • STUN is a protocol used to discover public IP addresses and port mappings allocated by NAT devices.
  • It helps determine the public IP address and port of a device from within a private network.
  • It is used for establishing direct peer-to-peer connections when both peers are not behind restrictive NATs or firewalls.

TURN (Traversal Using Relays around NAT)

  • TURN is a protocol used as a fallback mechanism when direct peer-to-peer communication via STUN is not possible.
  • In cases where STUN cannot establish a direct connection (due to symmetric NATs or firewalls), TURN servers act as relays to facilitate communication between peers.

Traversal Using Relays around NAT

ICE (Interactive Connectivity Establishment)

  • Before two peers can communicate using WebRTC, they need to exchange connectivity information.
  • Since The Network conditions can vary depending on several factors, an external service Is usually used for discovering the possible candidates for connecting to a peer this service Is Called ICE and is using either a STUN or a TURN server.


  • For establishing a connection between the peers RTCPeerConnection Instance helps to create a peer to peer connection with another RTC Instance in another browser
  • It takes an object as a parameter that contains STUN servers or TURN servers.


  • Information about peer media, security, IP Addresses everything to be exchanged to create a connection.


  • To send the SDP to the other peer and to send the candidates to the other peer we use signaling.
  • Signaling is not handled by WebRTC we must do It manually.

Peer To Peer Connection How?

  • Both A and B create an `RTCPeerConnection` object. For A, this is the start of the process. This object is responsible for handling the connection between them, including streaming audio, video, and sharing data.
  • A generates an “offer” using its `RTCPeerConnection`. This offer includes information about A’s media capabilities (like video formats and codecs it supports) and how it can be connected (based on its ICE candidates, which we’ll get to in a moment). A then sets this offer as its `LocalDescription`, which means it’s the description of A’s end of the connection.
  • A sends this offer to B, usually via a signaling server, which is a server that helps A and B find and communicate with each other initially.
  • When B receives the offer, it creates its own `RTCPeerConnection` object (if it hasn’t already) and sets A’s offer as its `RemoteDescription`. This means B now understands how A can be connected and communicated with.
  • In response, B generates an “answer” using its `RTCPeerConnection`. This answer is B’s way of saying, “Here’s how you can connect to me,” including its media capabilities and connection information. B then sets this answer as its `LocalDescription`.
  • B sends its answer back to A, also through the signaling server.
  • On receiving B’s answer, A sets it as its `RemoteDescription`. Now, A knows how to connect and communicate with B directly.
  • Throughout this process, both A and B also gather and exchange ICE candidates. These candidates are potential networking paths (like IP addresses and ports) that the peers can use to find the best route to connect with each other directly. This step is crucial for navigating through NATs (Network Address Translators) and firewalls.
  • Once A and B have successfully exchanged offers, answers, and ICE candidates, they can establish a direct P2P connection. They can now start sharing data, streaming video, and audio directly, without going through a server.
  • This P2P connection is what makes WebRTC so powerful for real-time communication, as it allows for high-quality, low-latency exchanges between users.

Spring boot with WebRTC

Follow below steps before running the application

1) Generate certificates:

write your local ip address of your computer/host like YOUR_LOCAL_IP =

please create an empty ssl folder under the project directory

command : mkdir ssl && openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ssl/private_key.pem -out ssl/certificate.pem -subj “//C=US//ST=California//L=San Francisco//O=MyOrganization//OU=MyDepartment//CN=<YOUR_LOCAL_IP>”

2) Update nginx.conf

change <YOUR_LOCAL_IP> with your local ip same as step 1

3) Update client.js file in resources

File location: src/main/resources/static/client.js

4) Build Docker Image

sudo docker-compose up -d –build

Read More | Exploring the Exciting Features of Spring Boot

Step 1: Create Dockerfile

This Dockerfile defines a multi-stage build process to build and package your Java application into a Docker image.

## Build stage

FROM maven:3.9.6-amazoncorretto-17 AS build


COPY pom.xml .

RUN mvn dependency:go-offline

COPY src/ /app/src/

RUN mvn clean package -DskipTests

# Step : Package image

FROM openjdk:17-jdk-slim

COPY –from=build /app/target/*.jar app.jar

EXPOSE 8080 8000

ENTRYPOINT [“java”, “-jar” , “app.jar”]

Step 2: NGINX Configuration

This NGINX configuration file defines how requests to our server should be handled, including proxying requests to our Spring Boot application and handling WebSocket connections.

server {

listen 80;

set $ip_address;

server_name localhost $ip_address;


return 301 https://$host$request_uri;



server {

listen 443 ssl;

set $ip_address;

server_name localhost $ip_address;


ssl_certificate /etc/nginx/ssl/certificate.pem;

ssl_certificate_key /etc/nginx/ssl/private_key.pem;


location / {

proxy_pass http://springboot:8080;

proxy_set_header Host $host;

proxy_set_header X-Real-IP $remote_addr;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

proxy_set_header X-Forwarded-Proto $scheme;



location /socket.io/ {

proxy_pass http://springboot:8000;

proxy_set_header Host $host;

proxy_set_header X-Real-IP $remote_addr;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

proxy_set_header X-Forwarded-Proto $scheme;

proxy_http_version 1.1;

proxy_set_header Upgrade $http_upgrade;

proxy_set_header Connection “Upgrade”;



Step 3: Application Configuration

Application.properties file



Step 4: Client-Side Code

Client.js file

Client.js file

Step 5: Web Socket Configuration

public class WebSocketConfig {

private String host;

private int port;

public SocketIOServer socketIOServer() throws Exception {
com.corundumstudio.socketio.Configuration config =
new com.corundumstudio.socketio.Configuration();
return new SocketIOServer(config);

Step 6: Web Configuration

public class WebConfiguration implements WebMvcConfigurer {

public void addViewControllers(ViewControllerRegistry registry) {

public void addCorsMappings(CorsRegistry registry) {

Step 7: Socket Handler

public class SocketHandler {
private final SocketIOServer server;
private static final Map<String, String> users = new HashMap<>();
private static final Map<String, String> rooms = new HashMap<>();

public SocketHandler(SocketIOServer server) {
this.server = server;

public void onConnect(SocketIOClient client) {
System.out.println(“Client connected: ” + client.getSessionId());
String clientId = client.getSessionId().toString();
users.put(clientId, null);

public void onDisconnect(SocketIOClient client) {
String clientId = client.getSessionId().toString();
String room = users.get(clientId);
if (!Objects.isNull(room)) {
System.out.println(String.format(“Client disconnected: %s from : %s”, clientId, room));
client.getNamespace().getRoomOperations(room).sendEvent(“userDisconnected”, clientId);
printLog(“onDisconnect”, client, room);

public void onJoinRoom(SocketIOClient client, String room) {
int connectedClients = server.getRoomOperations(room).getClients().size();
if (connectedClients == 0) {
client.sendEvent(“created”, room);
users.put(client.getSessionId().toString(), room);
rooms.put(room, client.getSessionId().toString());
} else if (connectedClients == 1) {
client.sendEvent(“joined”, room);
users.put(client.getSessionId().toString(), room);
client.sendEvent(“setCaller”, rooms.get(room));
} else {
client.sendEvent(“full”, room);
printLog(“onReady”, client, room);

public void onReady(SocketIOClient client, String room, AckRequest ackRequest) {
client.getNamespace().getBroadcastOperations().sendEvent(“ready”, room);
printLog(“onReady”, client, room);

public void onCandidate(SocketIOClient client, Map<String, Object> payload) {
String room = (String) payload.get(“room”);
client.getNamespace().getRoomOperations(room).sendEvent(“candidate”, payload);
printLog(“onCandidate”, client, room);

public void onOffer(SocketIOClient client, Map<String, Object> payload) {
String room = (String) payload.get(“room”);
Object sdp = payload.get(“sdp”);
client.getNamespace().getRoomOperations(room).sendEvent(“offer”, sdp);
printLog(“onOffer”, client, room);

public void onAnswer(SocketIOClient client, Map<String, Object> payload) {
String room = (String) payload.get(“room”);
Object sdp = payload.get(“sdp”);
client.getNamespace().getRoomOperations(room).sendEvent(“answer”, sdp);
printLog(“onAnswer”, client, room);

public void onLeaveRoom(SocketIOClient client, String room) {
printLog(“onLeaveRoom”, client, room);

private static void printLog(String header, SocketIOClient client, String room) {
if (room == null) return;
int size = 0;
try {
size = client.getNamespace().getRoomOperations(room).getClients().size();
} catch (Exception e) {
log.error(“error “, e);
log.info(“#ConncetedClients – {} => room: {}, count: {}”, header, room, size);

Step 8: Build Your Docker image

sudo docker-compose up -d –build


Spring Boot is a great tool for making WebRTC signaling servers, which help in running live communication apps like chat and video calls. It gives developers lots of tools to build strong, growable, and live chat applications easily and quickly.

Spring Boot makes the whole process of building these apps much simpler, thanks to its big collection of Spring tools. This is great for both beginners and experienced developers who want to make anything from chat apps to video conference systems.

If you or your company wants to start or improve your live communication apps, working with a Java Development Company that knows a lot about Spring Boot and WebRTC can be a big help. They can guide you through the tricky parts of making these apps work well in real time.

This kind of teamwork not only speeds up making good-quality apps but also makes sure that your tech projects help your business, taking full advantage of what WebRTC can do with the help and flexibility of Spring Boot.

Github Link :


Meet the idealistic leader behind Inexture Solutions – Mahipalsinh Rana! With over 15 years of experience in Enterprise software design and development, Mahipalsinh Rana brings a wealth of technical knowledge and expertise to his role as CTO. He is also a liferay consultant with over a decade of experience in the industry.

Bringing Software Development Expertise to Every
Corner of the World

United States



United Kingdom




New Zealand










South Africa