Deploying Socket.IO to Azure Web App [UPDATED!]

September 06, 2023

This blog was first published on August 21, 2021. This is an update to the original blog to take advantage of Azure’s native support for Socket.IO, which was released on August 21, 2023. (Exactly two years later, talking about coincidences!)

Building applications in today’s world requires real-time web functionality to applications. This used to be considered an extra, a nice to have, but in todays development world it is now considered required. So what is a real-time web functionality? The most common example is a real-time chat application. But it is so much more and much deeper in todays web environment. On a given day, you most likely interact with dozens of websites and I would wager the vast majority of them have some element of real-time communications. For example, Facebook and Twitter has real-time notifications in the browser. Your news websites might give you alerts on breaking news.

In the old days, the website might have been configured with a timer and simply refreshed every 60 seconds. This worked but created a lot of unnecessary noise between the client and the server. Enter real-time, bidirectional and event-based communication between the browser and the server.

There are several products that do this. The largest is Socket.IO. It’s been around for a while. It is open sourced and used by companies around the world – including Microsoft. Parts of Microsoft Office online and Yammer both continue to use Socket.IO today. That does not mean that they are the only player in this space. There are several companies who offer this service as either a paid/hosted service or through open-source libraries: including Microsoft that offers SignalR.

You might ask, why Socket.IO if SignalR is available? For me it was ease of deployment and online documentation. There is something to be said about a product that is used by millions of websites. A simple search of Socket.IO on Stack Overflow and you can see hundreds of code samples.

In this guide we are going to deploy Socket.IO into Azure as a NodeJS application. And in addition, we will take the sample chat application from Socket.IO website and show a few things that are possible.

Get Everything Ready

For this project I will be using VS Code, Node.js and NPM. If you haven’t already, you should install these items to your workstation before we get going. You need at least Node.js 10 or later.

From your workstation, create a new directory. Mine is called SocketIO. Launch VS Code and choose File | Open Folder and browse to your newly created folder.

Once VS Code is open, choose Terminal | New Terminal and run:

npm init

It will ask you a bunch of basic questions about your application. Feel free to answer these however you like. No decision here will break anything.

Next, we need to install Socket.IO, run:

npm install @azure/web-pubsub-socket.io

Next, we are going to install Express as the server Socket.IO will run under, run:

npm install express

We now have all the parts needed to build our Express Server running Socket.IO. Notice that we are using @azure/web-pubsub-socket.io in this project, instead of socket.io. Azure now natively supports Socket.IO. This means as developers, we can continue using the APIs Socket.IO library provides but let Azure handle managing client connections for us. You can learn more of the benefits of using an Azure-hosted approach here.

Create a file named .gitignore and add two items:


node_modules
.vscode

Building the Socket.IO Server

Now we need to setup our web server and integrate Socket.IO into Express. To do that, from VS Code, create a file named index.js at the root of the project. You are going to add this to the file:


const { Server } = require("socket.io");
const { useAzureSocketIO } = require("@azure/web-pubsub-socket.io");
let io = new Server(3000);
useAzureSocketIO(io, {
    hub: "Hub",
    connectionString: process.argv[2]
});
 
io.on('connection', (socket) => {
    console.log('a user connected');
    socket.on('disconnect', () => {
        console.log('user disconnected');
    });
 
    socket.on('chat message', (msg) => {
        io.emit('chat message', msg);
        console.log('message: ' + msg);
    });
});

There are a lot of things happening here so let’s talk about the important items.

At the top we are declaring our variables (const). We setup the server and import in the Azure version of Socket.IO.

In order to connect with Socket.IO service on Azure, we need to configure it properly. Refer to this step-by-step guide to learn about how to create a Socket.IO resource on Azure and how to get a connection string.

Below is a quick cheat-sheet.

  1. Go to https://portal.azure.com/
  2. Create a new reseource. Search for Socket.IO and find Web PubSub for Socket.IO. Select it.
  3. Create your new resource. It will default to Premium. Click Change and move it down to Free.
  4. Click Create and wait for the process to finish.
  5. Once the resource is created, you will find the Connection String under Keys

OK, back to the code. At the top in the fourth line is useAzureSocketIO and within it we define the hub. In my case, we have called it Hub. This is IMPORTANT. When you create the service below it will create a Hub with that name by default. You can change it (you should honestly change it in my opinion) by going to Key and the Client URL Generator at the bottom.

The next section starting with io.on is where we wire up Socket.IO to do something. The first section tells us that when someone connects to the server, we are going to write a message to the console log. Next we have a disconnect event (i.e. when they close the tab) and in this case we are going to again display a message that the user disconnected. Lastly, we have a ‘chat message’ event. Here, we do two things.

io.emit will send this message to everyone who is subscribed to this Socket.IO server and listening for ‘chat message’. The second item, we will again write this out to the console.

We could run this locally now. Make sure to replace with your ‘connectionString’ found on Azure.

node index.js “connection-string”

If it works, there are no errors, or anything. It just works. You can go to Live Trace Setting in your Socket.IO resource in Azure. Click on Open Live Trace Tool and you will see this:

Our Chat Application Website

I mentioned this is an adaptation of the Socket.IO learn project. You can head over to that site to see the original steps if you want.

Unlike their project, we are going to build our chat application with the Web Server and Socket.IO server running in a different namespace. Again, this is much more realistic than what happens in the real world.

For our website, we are going to create another project. First, we create a folder – I named mine ChatApp – and then you are going to open that folder within VS Code. A second instance of VS Code should be running now.

I really want to show that this “website” has no relationship to our previous project. So instead of using Express to run the website, I’m going to grab a VS Code extension called Live Server. Once Live Server is installed, you can click on “Go Live” from VS Code and it will start a local webserver for you on port 5500.

Inside of our ChatApp folder, create an index.html and add the following:


<!DOCTYPE html>
<html>
    <head>
        <title>Socket.IO chat</title>

        <!-- JQuery -->
        <script
            src="https://code.jquery.com/jquery-1.12.4.js"
            integrity="sha256-Qw82+bXyGq6MydymqBxNPYTaUXXq7c8v3CwiYwLLNXU="
            crossorigin="anonymous"></script>

        <style>
            body { margin: 0; padding-bottom: 3rem; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; }

            #mainBody { background: rgba(0, 0, 0, 0.15); padding: 0.25rem; position: fixed; bottom: 0; left: 0; right: 0; display: flex; height: 3rem; box-sizing: border-box; backdrop-filter: blur(10px); }
            #input { border: none; padding: 0 1rem; flex-grow: 1; border-radius: 2rem; margin: 0.25rem; }
            #input:focus { outline: none; }
            #form > button { background: #333; border: none; padding: 0 1rem; margin: 0.25rem; border-radius: 3px; outline: none; color: #fff; }

            #messages { list-style-type: none; margin: 0; padding: 0; }
            #messages > li { padding: 0.5rem 1rem; }
            #messages > li:nth-child(odd) { background: #efefef; }
        </style>
    </head>
    <body>
        <ul id="messages"></ul>
        <div id="mainBody" action="">
            <input id="input" autocomplete="off" />
            <button id="btnSend">Send</button>
        </div>

        <script src="https://cdn.socket.io/4.1.2/socket.io.min.js" integrity="sha384-toS6mmwu70G0fw54EGlWWeA4z3dyJ+dlXBtSURSKN4vyRFOcxd3Bzjj/AoOwY+Rg" crossorigin="anonymous"></script>
        <script>
            const socket = io("<socketio-service-endpoint>", {path: "/clients/socketio/hubs/Hub",});

            $(document.body).on('click', '#btnSend', () => {
                console.log('click button');
                socket.emit('chat message', input.value);
                input.value = '';
            });

            socket. On('chat message', function(msg) {
                console.log('received');
                $("#messages").append('<li>' + msg + '</li>');
            });
        </script>
    </body>
</html>

Lets talk about what we have above. The top is loading jQuery and some CSS. In the body of the HTML we have three items. First is a UL that we will append LI items to when messages are sent or received. You have the input text and a button to send your message.

In the script tag, we load Socket.IO from a CDN location. Below that, we create an instance of the socket. Note that this socket.io client connects with the Socket.IO service running on Azure. Make sure to replace “socketio-service-endpoint” with your own found on Azure portal. This is the same spot we looked at the Hub previously. We need the full URLs as we need to copy where we are connecting here.

Below that we have our actions. First, is a click action for when the user clicks the btnSend button, we log the action to the browser console and emit it to the Socket.IO Server.

Directly below that, we have a socket.on function. When a ‘chat message’ event if received, we log the action and append the message to the UI we listed above creating a chat experience.

Remember, make sure to have your other project still running on port 3000.

Deploy to Azure

We now have our working demo of a Chat Application. Now we want to deploy the Socket.IO portion to Azure. Your first question might be:

I created a resource for Socket.IO, do I really still need to “deploy a server”. And the answer is yes. What you built previously was a Web PubSub for Socket.IO service. Recall, the server is where it has all the rules. See the below image:

What Microsoft has done here is created a solution to manage the connections. If you scaled Socket.IO on your own, you need to deploy an adapter, get other services involved, etc. Now you might ask, if I’m running this for millions of clients, should I have more than one Socket.IO Server. Yes. But I don’t need to load balance or create complex scenarios. I simply need a second server and the Web PubSub for Socket.IO will figure out the rest. See here:

Let’s create our resources now.

In the resulting page, search for Web App.

On the resulting page, you will select the options for your Web App. A few of these are very important. You can select any Subscription and Resource Group. Under the Runtime Stack, select Node 14 LTS. Ensure the operating system is Linux and select your desired region.

NOTE: Although my image shows a basic B1 and the previous blog mentioned that that Free Tier did not support Web Sockets. That is no longer the case. Feel free to use the Free Tier.

On Configuration | General Settings of your web app, you will want to specify the startup command we used above. Obviously, this isn’t super secure and shouldn’t be used in the long term, but you can see it all works.

The last step is the easiest. We need to publish your application from VS Code to Azure. So ensure you have the Azure App Service extension installed in your VS Code instance.

Right click on the App Service instance you just created and choose Deploy to Web App. It will ask you for the folder you want to deploy, it should be the current one, and in a few minutes your site will be deployed.

How Do I Know It Worked

Option #1: Go to the App Service Logs of your server. Enable them. Then go to Log stream. If you wait around long enough, you will see the dump of logs to the screen:


Built using Gatsby and Material-UI

Copyright © TheArgyleMVP 2023.