<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Saurav M H</title>
    <description>The latest articles on DEV Community by Saurav M H (@sauravmh).</description>
    <link>https://dev.to/sauravmh</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F420581%2Fbce3b0de-7033-4c86-b9b1-2a26033ed9fc.png</url>
      <title>DEV Community: Saurav M H</title>
      <link>https://dev.to/sauravmh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sauravmh"/>
    <language>en</language>
    <item>
      <title>Browser Game Design using WebSockets and Deployments on Scale - Part 2</title>
      <dc:creator>Saurav M H</dc:creator>
      <pubDate>Wed, 30 Sep 2020 18:08:36 +0000</pubDate>
      <link>https://dev.to/sauravmh/browser-game-design-using-websockets-and-deployments-on-scale-1iaa</link>
      <guid>https://dev.to/sauravmh/browser-game-design-using-websockets-and-deployments-on-scale-1iaa</guid>
      <description>&lt;p&gt;I would definitely recommend you to read the first article before we continue the journey here -&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/sauravmh" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F420581%2Fbce3b0de-7033-4c86-b9b1-2a26033ed9fc.png" alt="sauravmh"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/sauravmh/building-a-multiplayer-game-using-websockets-1n63" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Building a multiplayer game using WebSockets - Part 1&lt;/h2&gt;
      &lt;h3&gt;Saurav M H ・ Jul 6 '20&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#javascript&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#react&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#node&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;
 

&lt;h1&gt;
  
  
  A gist of part 1 of the series:
&lt;/h1&gt;

&lt;p&gt;In the last article, we talked about how to create a browser turn-based multiplayer game using socket.io and NodeJS. &lt;/p&gt;

&lt;p&gt;The topics covered were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using Football Draft as an example of a turn-based game&lt;/li&gt;
&lt;li&gt;The server architecture overview and folder structure&lt;/li&gt;
&lt;li&gt;Introducing socket.io and handling exposed ports&lt;/li&gt;
&lt;li&gt;Creation of rooms and namespaces and some user actions&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Let's continue from where we left
&lt;/h1&gt;

&lt;p&gt;We will do system design for generic turn-based games here. Let's proceed with scenarios in order of user interactions.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User enters the homepage&lt;/li&gt;
&lt;li&gt;After the user creates or joins a new room&lt;/li&gt;
&lt;li&gt;Waiting till others arrive before starting the game&lt;/li&gt;
&lt;li&gt;Rotating turns&lt;/li&gt;
&lt;li&gt;Handling player exits in-game&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  👋 Users enter the homepage
&lt;/h2&gt;

&lt;p&gt;This can be your welcome page. In my case, I have added one previous page reading the username/alias. Here we explain the users the rules of the game and show users a clear option to join or create a new room for them to play.&lt;/p&gt;

&lt;h3&gt;
  
  
  Client Side
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsst8zicg480mbbo3w88w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsst8zicg480mbbo3w88w.png" alt="homepage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  BTS
&lt;/h3&gt;

&lt;p&gt;You can always refer the whole documented code from my GitHub links provided at the end.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;join&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// @optional Check if correct password for room&lt;/span&gt;
    &lt;span class="c1"&gt;// Check if room size is equal to or more than 1&lt;/span&gt;
    &lt;span class="c1"&gt;//     If yes, join the socket to the room&lt;/span&gt;
    &lt;span class="c1"&gt;//     If not, emit 'invalid operation: room does not exist'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;create&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Check if room size is equal to zero&lt;/span&gt;
    &lt;span class="c1"&gt;//     If yes, create a new room and join socket to the room&lt;/span&gt;
    &lt;span class="c1"&gt;//     If not, emit 'invalid operation: room already exists'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  👥 After: User Creates or Joins the Room
&lt;/h2&gt;

&lt;p&gt;After a user creates a room or starts a new game, a &lt;code&gt;gameState&lt;/code&gt; is created for the given &lt;code&gt;roomId&lt;/code&gt;. GameState is essentially a central state management section on your server. All your client actions will be validated and updated on this gameState.&lt;/p&gt;

&lt;p&gt;The state can be a simple Javascript object or a table/collection in your database. The reasons you might want to use a database instead of a simple JS object might be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have longer game sessions

&lt;ul&gt;
&lt;li&gt;Reason: Chances are the server instance that might restart or crash due to some reason. Using a database for the &lt;code&gt;gameState&lt;/code&gt; management helps you mitigate this problem&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;There are multiple server sessions running

&lt;ul&gt;
&lt;li&gt;Reason: It is usually a good practice to run multiple instances of your socketio or NodeJS processes when running on scale. You can check out the node cluster module for this. Scaling is explained in detail later 😌 &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yes, in my case I am storing state in a JS object (Stop attacking me, Jesus!). Well, I didn't think of scale at the start of the project and I'm glad I didn't go down this rabbit hole. But the silver lining is, you can easily plug in a Redis DB when initializing the socketio object. The rest will be handled by the library. But again, we want to take this a few steps further 🚀 I have explained the project scaling in detail later on in this article!&lt;/p&gt;
&lt;h3&gt;
  
  
  BTS
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$2y$04$qE0oJbl7eixKMLhS7u6ure9wS/I1wcA.DtJOhaMe3oqsa1rQKAEO6&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Storing hash, coz well security!&lt;/span&gt;
    &lt;span class="na"&gt;clients&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;socker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Default socket.io client-session id&lt;/span&gt;
        &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// User alias/username&lt;/span&gt;
        &lt;span class="na"&gt;isReady&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="c1"&gt;// Default&lt;/span&gt;
    &lt;span class="p"&gt;}...]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  🕑 Waiting time till everyone is Ready
&lt;/h2&gt;

&lt;p&gt;We just can't start the game when a selected number of users join the game. Users must confirm they are ready, and once every user is ready the game starts.&lt;br&gt;
&lt;em&gt;Optional - allow users to unready themselves&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Client Side
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fh96n1ki8yxotxfvddp9b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fh96n1ki8yxotxfvddp9b.png" alt="client-side"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  BTS
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="cm"&gt;/**
 * Mark player as ready  ---&amp;gt; to start the draft in the given room. If all players are ready then initiate the draft
 *
 * @access public
 */&lt;/span&gt;
&lt;span class="nf"&gt;isReady&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;socker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;is-ready&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// 1. Flip the player's `isReady` state to true (only for the player which emitted this event)&lt;/span&gt;
        &lt;span class="c1"&gt;// 2. If all players are ready then trigger beginDraft()&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  🔄 Rotating Turns
&lt;/h2&gt;

&lt;p&gt;You might think of this as the core part of the game logic. We basically rotate the chance to pick items amongst the players. Think of the &lt;code&gt;clients&lt;/code&gt; array as a Circular Queue. For this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We will first randomize the &lt;code&gt;clients&lt;/code&gt; queue (&lt;code&gt;this.store.clients&lt;/code&gt;) order.&lt;/li&gt;
&lt;li&gt;Start a timeout for each player's turn. Auto pick/don't pick an item on timeout expiry. (I have gone with no items pick on timeout expiry)&lt;/li&gt;
&lt;li&gt;Rotate the chances on the whole queue, until the required number of rounds are reached&lt;/li&gt;
&lt;li&gt;Update the &lt;code&gt;gameState&lt;/code&gt; on every update from the player turn.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Again, the above steps are just my game logic. You can tweak them according to your requirements. Just make sure the &lt;code&gt;gameState&lt;/code&gt; is up-to-date after each user action. You might run into consistency issues otherwise&lt;/p&gt;
&lt;h3&gt;
  
  
  BTS
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

 &lt;span class="cm"&gt;/**
 * Consume player item and update the gameState. Reset the timeout and initiate the next turn.
 *
 * @access    public
 */&lt;/span&gt;
&lt;span class="nf"&gt;shiftTurn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;socker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;player-turn-trigger&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selectedItem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentChance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;socker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// 1. Update the gameState&lt;/span&gt;
            &lt;span class="c1"&gt;// 2. Add the selectedItem to the userItems list&lt;/span&gt;
            &lt;span class="c1"&gt;// 3. resetTimeout()&lt;/span&gt;
            &lt;span class="c1"&gt;// 4. trigger nextTurn()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  🚫 Handling Player Exits inGame
&lt;/h2&gt;

&lt;p&gt;It is very important to handle player exits inGame. The user may choose to exit using the in-game menu or just close the application or his/her internet connection might just die (poor lad! we all have been there). Under all these circumstances it is important to make sure your application doesn't crash. This may affect other players' games.&lt;/p&gt;

&lt;p&gt;For our case we need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clear all the timeouts inGame&lt;/li&gt;
&lt;li&gt;Broadcast the last synced list of items for all users in the current room&lt;/li&gt;
&lt;li&gt;Reset the current &lt;code&gt;gameState&lt;/code&gt; or continue the game by removing &lt;code&gt;disconnected-user&lt;/code&gt; from the player queue&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
  
  
  Deploying the application
&lt;/h1&gt;
&lt;h2&gt;
  
  
  CI/CD for React Application
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6oi729imfav7b1xi920k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6oi729imfav7b1xi920k.png" alt="vercel-CI/CD"&gt;&lt;/a&gt;&lt;/p&gt;
 Add your GitHub URL and click to deploy 



&lt;p&gt;This is the easiest deployment stage of the pipeline. You can use Vercel/Netlify or other free (I do mean generously free!) auto build and deploy tools. You just need to add your GitHub project URL on the Vercel dashboard and click deploy (yes indeed very easy).&lt;/p&gt;
&lt;h2&gt;
  
  
  Deploying the HTTP and Websockets Server
&lt;/h2&gt;

&lt;p&gt;Before discussing the "continuous" part of CI/CD, let's see how do we set up the deployment.&lt;/p&gt;

&lt;p&gt;TLDR;&lt;br&gt;
We will be using Nginx as a reverse proxy server, creating two virtual hosts: one for HTTP requests and another for WebSockets requests.&lt;/p&gt;

&lt;p&gt;It's okay if you didn't understand some or any part of the above. Even if you did, and are curious about the details, I will be elaborating the same with concise examples.&lt;/p&gt;
&lt;h2&gt;
  
  
  What is Nginx?
&lt;/h2&gt;

&lt;p&gt;It is a web server that can be used as a reverse proxy, load-balancer, mail-server, handling cache, etc. It handles large amounts (up to millions) of requests and yet is light-weight and super-modular to use.&lt;/p&gt;

&lt;p&gt;But, for our use case, we will be using Nginx as reverse-proxy. Before you ask,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A reverse proxy is a server that sits in front of one or more web servers, intercepting requests from clients.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8vo5u7nyvhy1yrg1r7gb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8vo5u7nyvhy1yrg1r7gb.png" alt="reverse-proxy-flow"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Creating Virtual Hosts
&lt;/h2&gt;

&lt;p&gt;Virtual Hosts are more of an Apache (It's a webserver just like Nginx) Term. Nginx coins this as "server blocks"&lt;/p&gt;

&lt;p&gt;You can point each server block to a domain/subdomain you want. Here, we are creating two subdomains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;soc.mydomain.com&lt;/code&gt; -&amp;gt; Endpoint for websockets connections&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;api.mydomain.com&lt;/code&gt; -&amp;gt; Endpoint for HTTP connections&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, to keep the whole configuration modular, we will be following a standard folder structure.&lt;/p&gt;

&lt;p&gt;You will see a similar recommended template in Nginx docs too, this one has additional configs which will make writing configs for each &lt;code&gt;host&lt;/code&gt; a breeze!&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;./conf.d/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;error-pages.conf&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;pages&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;each&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;code&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;gzip.conf&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;standard&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;gzip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;configs&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;url-filter-cgi.conf&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Filter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;urls&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;status&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;real-ip-resolution.conf&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Uses&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;real-client-ip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;cloudflare&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;amazon&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;proxies&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;└──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;./vhost.d/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;api.mydomain.com.conf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;HTTP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;config&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="err"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;user-config&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;soc.mydomain.com.conf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Websockets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;config&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;user-config&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;└──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;_default.conf&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;nginx.conf&lt;/span&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;global-default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;nginx&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;mime.types&lt;/span&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;allow-list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;mime&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;types&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;span class="err"&gt;└──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here, &lt;code&gt;./vhost.d/&lt;/code&gt; is where we place all user-generated configs.&lt;/p&gt;

&lt;p&gt;Now let us configure a server block for handling HTTP requests,&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;───────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;File:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;api.mydomain.com.conf&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;───────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;listen&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;listen&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;::&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;server_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;api.mydomain.com;&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;conf.d/error-pages.conf;&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;conf.d/url-filter*.conf;&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="err"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;301&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;https://$host$uri$is_args$args;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;ssl_certificate&lt;/span&gt;&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="err"&gt;/my_cert_path/api.mydomain.com/fullchain.pem;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;ssl_certificate_key&lt;/span&gt;&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="err"&gt;/my_cert_path/api.mydomain.com/privkey.pem;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;ssl_trusted_certificate&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="err"&gt;/my_cert_path/api.mydomain.com/chain.pem;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;listen&lt;/span&gt;&lt;span class="w"&gt;                              &lt;/span&gt;&lt;span class="mi"&gt;443&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ssl;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;server_name&lt;/span&gt;&lt;span class="w"&gt;                         &lt;/span&gt;&lt;span class="err"&gt;api.mydomain.com;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;conf.d/error-pages.conf;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;conf.d/url-filter*.conf;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/home/saurav/my_application;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="err"&gt;proxy_pass&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;http://localhost:&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="err"&gt;/;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="err"&gt;proxy_http_version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;33&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="err"&gt;proxy_set_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Upgrade&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$http_upgrade;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;34&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="err"&gt;proxy_set_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Connection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'upgrade';&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="err"&gt;proxy_set_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$host;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="err"&gt;proxy_cache_bypass&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$http_upgrade;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;37&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="err"&gt;proxy_hide_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;X-Powered-By;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;38&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;39&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;



&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here, we open the port 80 for internet communication, HTTP protocol to be specific. The &lt;code&gt;server_name&lt;/code&gt; is the endpoint you want to create a virtual host. In simple words, the public endpoint you want to route your requests to.&lt;/p&gt;

&lt;p&gt;We will discuss both the server blocks in detail, after the below config.&lt;/p&gt;

&lt;p&gt;Let us take an example for configuring a WebSockets enabled server block.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;───────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;File:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;soc.mydomain.com.conf&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;───────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;listen&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;listen&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;::&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;server_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;soc.mydomain.com;&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;conf.d/error-pages.conf;&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;conf.d/url-filter*.conf;&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="err"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;301&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;https://$host$uri$is_args$args;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;ssl_certificate&lt;/span&gt;&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="err"&gt;/my_cert_path/soc.mydomain.com/fullchain.pem;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;ssl_certificate_key&lt;/span&gt;&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="err"&gt;/my_cert_path/soc.mydomain.com/privkey.pem;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;ssl_trusted_certificate&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="err"&gt;/my_cert_path/soc.mydomain.com/chain.pem;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;listen&lt;/span&gt;&lt;span class="w"&gt;                              &lt;/span&gt;&lt;span class="mi"&gt;443&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ssl;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;server_name&lt;/span&gt;&lt;span class="w"&gt;                         &lt;/span&gt;&lt;span class="err"&gt;soc.mydomain.com;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;conf.d/error-pages.conf;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;conf.d/url-filter*.conf;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/var/www/my_application;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="err"&gt;proxy_pass&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;http://localhost:&lt;/span&gt;&lt;span class="mi"&gt;3001&lt;/span&gt;&lt;span class="err"&gt;/;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="err"&gt;proxy_redirect&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;off;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;33&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;34&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="err"&gt;proxy_http_version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="err"&gt;proxy_set_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;X-Real-IP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$remote_addr;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="err"&gt;proxy_set_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;X-Forwarded-For&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$proxy_add_x_forwarded_for;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;37&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="err"&gt;proxy_set_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$host;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;38&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;39&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="err"&gt;proxy_set_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;X-Forwarded-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$host;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="err"&gt;proxy_set_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;X-Forwarded-Server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$host;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;41&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="err"&gt;proxy_set_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Upgrade&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$http_upgrade;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;43&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="err"&gt;proxy_set_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Connection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"upgrade"&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;44&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;46&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  The first server block
&lt;/h3&gt;

&lt;p&gt;Creates a &lt;code&gt;301&lt;/code&gt; redirect from the virtual host location, &lt;code&gt;soc.mydomain.com&lt;/code&gt; in the above example to an https connection. If you do not require an SSL connection, you can choose to define your configs here itself.&lt;/p&gt;
&lt;h3&gt;
  
  
  The second server block
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Add SSL certificates location (I use certbot to generate SSL certs, feel free to explore other options). This step is not necessary if you are using Cloudflare, Amazon, or any other edge delivery proxy services, as you can configure the certs from their portal.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;proxy_pass&lt;/code&gt;: Point to the server accepting the client requests. In our case, we are running the WebSockets backend on the same server, hence we add a proxy_pass for our localhost connection.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;proxy_set_header&lt;/code&gt;: Adding appropriate request headers. 

&lt;ul&gt;
&lt;li&gt;Here, we set the &lt;code&gt;Connection "upgrade"&lt;/code&gt; to allow switching protocols from &lt;code&gt;polling&lt;/code&gt; to &lt;code&gt;websockets&lt;/code&gt;. This feature is tightly bound to &lt;code&gt;socket.io&lt;/code&gt;, as they use this feature to support older browsers. You may skip this header if you are using &lt;code&gt;websockets&lt;/code&gt; directly&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;X-Forwarded-Host&lt;/code&gt;: The original host requested by the client in the Host HTTP request header&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;X-Forwarded-Server&lt;/code&gt;: The hostname of the proxy server.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;X-Forwarded-For&lt;/code&gt;: Automatically append &lt;code&gt;$remote_addr&lt;/code&gt; to any incoming &lt;code&gt;X-Forwarded-For&lt;/code&gt; headers.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;X-Real-IP&lt;/code&gt;: This might be tricky to understand, but bear with me. Assume a user is at IP &lt;code&gt;A&lt;/code&gt;, the user is behind a proxy &lt;code&gt;B&lt;/code&gt;. Now the user sends a request to loadbalancer with IP &lt;code&gt;C&lt;/code&gt;, which routes it to Nginx. After Nginx has processed the request, the requests will have the following headers:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;X-Forwarded-For: [A, B, C]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;X-Real-IP: B&lt;/code&gt;: Since Nginx will recurse on &lt;code&gt;X-Forwarded-For&lt;/code&gt; from the end of the array to the start of the array, and find the first untrusted IP.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;X-Forwarded-For&lt;/code&gt; does not exist in a request, then &lt;code&gt;$remote_addr&lt;/code&gt; value is used in the &lt;code&gt;X-Real-IP&lt;/code&gt; header, otherwise, it is overwritten by recursing on the &lt;code&gt;X-Forwarded-For&lt;/code&gt; header array, taking into consideration set_real_ip_from rule(s).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, we have seen how to configure reverse proxies to serve your application over the internet, be it HTTP requests or WebSocket connections. The next important part is how to handle the load and horizontal scaling of your application. Do we even require scaling? If yes, under what specific conditions?&lt;/p&gt;

&lt;p&gt;All of the above questions and many others are answered in the below section.&lt;/p&gt;
&lt;h2&gt;
  
  
  🚀 Scaling your application
&lt;/h2&gt;

&lt;p&gt;There are basically two kinds of scaling&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vertical Scaling: Increasing the server capacity to handle and process more requests&lt;/li&gt;
&lt;li&gt;Horizontal Scaling: Increasing the server instances, to distribute and process more requests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will be focusing more on horizontal scaling here. More specifically, focusing on scaling NodeJS applications. Even though some methods can be used for scaling other than NodeJS, details for other platform applications are out of the scope of this article.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fefa3iatf1ntsq6mb2er4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fefa3iatf1ntsq6mb2er4.png" alt="node network-balancing //Credits: https://medium.com/iquii/good-practices-for-high-performance-and-scalable-node-js-applications-part-1-3-bb06b6204197"&gt;&lt;/a&gt;&lt;/p&gt;
 Network Balancing Overview 


&lt;h3&gt;
  
  
  When do I scale?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;First off, make sure your NodeJs process is ONLY using asynchronous I/O. If it's not compute-intensive and using asynchronous I/O, it should be able to have many different requests "in-flight" at the same time. The design of node.js is particularly good at this if your code is designed properly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Second, instrument and measure, measure, measure. Understand where your bottlenecks are in your existing NodeJS server and what is causing the delay or sequencing you see. Sometimes there are ways to dramatically fix/improve your bottlenecks before you start adding lots more clusters or servers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Third, use the node.js cluster module. This will create one master node.js process that automatically balances between several child processes. You generally want to create a cluster child for each actual CPU you have in your server computer since that will get you the most use out of your CPU.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fourth, if you need to scale to the point of multiple actual server computers, then you would use either a load balancer or reverse proxy such as Nginx to share the load among multiple hosts. If you had a quad-core CPUs in your server, you could run a cluster with four NodeJS processes on it on each server computer and then use Nginx to balance among the several server boxes you had.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that adding multiple hosts that are load balanced by Nginx is the last option here, not the first option.&lt;/p&gt;
&lt;h3&gt;
  
  
  How to scale a NodeJS application?
&lt;/h3&gt;

&lt;p&gt;As mentioned, you can use the &lt;code&gt;node cluster&lt;/code&gt; module. But in this example, we will be using pm2.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;PM2 is a daemon process manager that will help you manage and keep your application online&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcdnox8319gdtyjms26sz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcdnox8319gdtyjms26sz.png" alt="pm2-monitoring-screenshot"&gt;&lt;/a&gt;&lt;/p&gt;
 My pm2 monitoring on server 



&lt;p&gt;Apart from being an excellent monitoring tool for your server jobs, there are various abstractions pm2 provides which makes it the go-to manager for deployments.&lt;br&gt;
It also includes &lt;code&gt;cluster mode&lt;/code&gt;, which is a clean abstraction built over the &lt;code&gt;node-cluster&lt;/code&gt; module.&lt;/p&gt;

&lt;p&gt;An example use-case would be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;code&gt;deploy_processes.json&lt;/code&gt; file
```json
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;{&lt;br&gt;
  script    : "server.js",&lt;br&gt;
  instances : "max",&lt;br&gt;
  exec_mode : "cluster"&lt;br&gt;
}&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Run `pm2 start deploy_processes.json`
- Run Reload after any changes: `pm2 reload deploy_processes.json`. This allows for reloading with 0-second-downtime, as opposed to `pm2 restart`, which kills and starts the process again. (*This statement is taken from the official docs, I've not made it up*)

Make sure while scaling in general, your application is **StateLess**. Do not store any information in the process or anywhere in runtime. You may use RedisDB (in-memory storage), MongoDB, or any storage of your choice to share states between the processes.

Also when scaling NodeJS applications, make sure you are not spawning many **child processes**. This just creates a lot more processes than your CPUs, causing a context switching hell for the OS.

## 🤔 Going ServerLess, are we?

Maybe. Handling scaling, errors, monitoring, and what not! becomes a pain once your application gains more users. I nowhere remotely have such a huge userbase, so I did not need serverless in my case. But it is indeed an interesting and vast field. I am currently porting this project to AWS lambdas and utilizing their other services.

Maybe I will save my server cost, maybe not.
Maybe I will have better request response times, maybe not.
Maybe I will scale this properly, maybe not.

One thing I know for sure, this path will be super interesting and a pretty good learning experience too. I had started this project with the primary focus of playing with DevOps, and I don't intend to stop now.

**If you are interested, here are my project links:**

- Backend (Websockets + HTTP) - [https://github.com/sauravhiremath/fifa-api](https://github.com/sauravhiremath/fifa-api)
- Frontend (ReactJS) -  [https://github.com/sauravhiremath/fifa](https://github.com/sauravhiremath/fifa)
- WebCrawler (Python3 + Scrapy) - [https://github.com/sauravhiremath/fifa-stats-crawler](https://github.com/sauravhiremath/fifa-stats-crawler)

&amp;gt; _Lemme know if you have any questions or suggestions for future articles_

&amp;gt; ✌️**_️ Have a great day!_**
&amp;gt; 
&amp;gt; Follow me on twitter @[sauravmh](https://twitter.com/sauravmh) for updates and maybe some cool stuff!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>linux</category>
      <category>react</category>
    </item>
    <item>
      <title>Going OpenSource - A dive into facebook's jest</title>
      <dc:creator>Saurav M H</dc:creator>
      <pubDate>Tue, 11 Aug 2020 10:33:14 +0000</pubDate>
      <link>https://dev.to/sauravmh/going-opensource-a-dive-into-facebook-s-jest-cgb</link>
      <guid>https://dev.to/sauravmh/going-opensource-a-dive-into-facebook-s-jest-cgb</guid>
      <description>&lt;h2&gt;
  
  
  Authors
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://twitter.com/sauravmh" rel="noopener noreferrer"&gt;Saurav M. H&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/kush_kunal" rel="noopener noreferrer"&gt;Kunal Kushwaha&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  What is MLH Fellowship?
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Firwbxy085wu5ca7pc3n4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Firwbxy085wu5ca7pc3n4.jpg" alt="MLH-fellowship" width="" height=""&gt;&lt;/a&gt;&lt;br&gt;
The MLH Fellowship is an internship alternative for software engineers, with a focus on Open Source projects. Instead of working on a project for just one company, students contribute to Open Source projects that are used by companies around the world. It is a great way to get real-world software development experience from the comfort of your home. The open-source community is very helpful and encourages new developers to take part in their organizations. One gains exposure, can test their skills, gain knowledge, and bond with the community to produce quality code that helps people around the world.&lt;/p&gt;
&lt;h1&gt;
  
  
  How is it different from other Open Source programs?
&lt;/h1&gt;

&lt;p&gt;At the beginning of the program, fellows are placed into small groups called “pods” that collectively contribute to the assigned projects as a team under the educational mentorship of a professional software engineer.  Apart from work, the fellowship program also provides opportunities to build a network and have fun while doing so! Students get to work on the latest Open Source technologies and are matched with projects according to their skills and interest, providing students with a learning opportunity while contributing to real-world projects. But, it’s not just about coding. Soft-skills and team-building exercises are conducted by MLH regularly, in addition to technical hands-on workshops! It’s a remote opportunity but provides a global platform for students to showcase their skills. During the Fellowship, we contributed to the Facebook/Jest project. &lt;/p&gt;
&lt;h1&gt;
  
  
  What is Jest?
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnk7d6gy4iyubnthvklec.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnk7d6gy4iyubnthvklec.png" alt="Jest" width="" height=""&gt;&lt;/a&gt;&lt;br&gt;
Well, this was the opportunity we were presented at the start of the fellowship. We were over the moon to have got this project!&lt;/p&gt;

&lt;p&gt;Jest is a JavaScript testing framework designed to ensure the correctness of any JavaScript codebase. It allows you to write tests with an approachable, familiar, and feature-rich API that gives you results quickly. Jest is well-documented, requires little configuration, and can be extended to match your requirements. Jest makes testing delightful. &lt;/p&gt;
&lt;h2&gt;
  
  
  Where did we start?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Before contributing to any open source projects, you must use it. You would find it very difficult to contribute if you don't know what the project is supposed to be doing. That's how we started. Using Jest to write our tests for applications we had created before. &lt;/li&gt;
&lt;li&gt;Following the first week of the MLH fellowship, we had a meeting with the contributors of Jest to better understand the roadmap of the tasks and projects assigned to us. It was a productive session and helped us gain insight into the project. Reaching out to the contributors is highly recommended if you get stuck while contributing to any open source project. You can reach out to the community members via the mailing list. &lt;/li&gt;
&lt;li&gt;The next stage was understanding how the project works. This was the week of diving deep into the code base of Jest. The documentation &amp;amp; conference talks come in handy while doing so. Since you are working on the project as a beginner, it is always a good idea to provide future contributors a form of guide that will help them in contributing, just like we are doing with this blog! Another way of getting familiar with the project is debugging the workflow &amp;amp; taking notes via discussions to further research upon. Coming to how to start making contributions, it is suggested that one starts with some beginner-friendly issues if they are new to the project. This is a great way to get some momentum going and getting familiar with the contribution guidelines as well. &lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Do we need to master using Jest to contribute? 🤞
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;You don't need to be an expert to contribute to Open Source. If you are a beginner, you can surely find projects that can help you grow your skillset and get real-world software development experience. If there is a learning curve involved, like there was in Jest for us, that is a good thing because now you have a learning opportunity while making contributions. &lt;/li&gt;
&lt;li&gt;Coming to the point of how to understand such large codebases? Well, you don't. The project is divided into individual packages that make it easier for you to navigate and explore the codebase. You can have a general idea about the workflow. You can dive deep into packages separately when required to contribute to it. For this, you can take a look at the issues section of the GitHub repository, and filter issues with easy to get started ones. And ofc, if you get stuck anywhere, the community is there to help you!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Okay, I know the bug/feature proposal. Where do I start making changes? 🤔
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;It starts by opening up an issue. Your issue should be well documented and explain the motivation behind it. If you are requesting a new feature, you should mention what the feature is, how one can go forward to implement it &amp;amp; why it is important. If your issue relates to solving a bug, you should mention how to reproduce that bug. What changes are breaking due to it &amp;amp; what the expected behavior should be? You should have a detailed explanation of what you want to achieve and how to achieve it. Ask for feedback on your issue from the community members to get more insights on it.&lt;/li&gt;
&lt;li&gt;Documenting is crucial as it helps others help you. If you are already familiar with how to solve the issue, you can open a pull request for the same. Documentation plays an important role here as well. You should mention what changes you made and why. What issues you were facing and how you fixed them. If the change that you have made is going to affect the existing codebase. And remember, don't forget to add a line in the logs!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  The workflow of a test run 🚀
&lt;/h2&gt;

&lt;p&gt;I believe this post by Kunal does justice to it &lt;a href="https://dev.to/kunal/jest-architecture-24fp"&gt;Jest-architecture&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The importance of community 👥
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6a84qgwh2wt6htlggi9t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6a84qgwh2wt6htlggi9t.png" alt="Opensource" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In your open source journey, the community will play a very important role. The sole purpose of having a community is to make collaborations and learning easier for everyone. This lets us create software that is used and. contributed to by people around the world. From a beginner's point of view, your interaction with the community is what's going to help you at most times. In times when you are facing a blocker, need more input and suggestions on a particular topic, or want to get your PR reviewed, the community members are the ones who will point you in the right direction as they know the project inside out. Your peers are also a major motivation. Taking an example of the pair programming sessions/debugging we had, helped us resolve bugs (more about that later) in a faster and efficient way. &lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  How to ask questions &amp;amp; request feedback
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7bjaox60jv34bzstnjz4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7bjaox60jv34bzstnjz4.jpg" alt="Questions" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Don't just say Hi in chat! This can’t be stressed enough. Everyone is quite busy with their lives, including you. So add a short and concise form of your question in the discussion channels. Tag an appropriate person (look at the channel rules first).&lt;/li&gt;
&lt;li&gt;Try providing links or short-reproducible forms of your problem to the other person. This increases the chance of your question getting more attention and solved sooner.&lt;/li&gt;
&lt;li&gt;Ask 10 short questions instead of a long one (not too short). Asking concise questions helps the person in receiving an answer sooner, as not much time is spent in understanding the context of the text as compared to say a long question.&lt;/li&gt;
&lt;li&gt;This brings us to another good point, break large PRs into smaller ones if possible! This is highly encouraged as it helps the reviewer understand the changes in a more simplified way and this breaking down of process leads to effective discussions and feedback. &lt;/li&gt;
&lt;li&gt;Mention the steps to reproduce the error in your message, so that others can know what you are dealing with. Also mention what you tried to fix it, and what it led to, to avoid duplicate answers and things like "I already tried that".&lt;/li&gt;
&lt;li&gt;Requesting feedback is important when making contributions. Showcase your work in a well-defined manner, so that it is clear what you had tried to achieve. This includes providing information about changes you made and how it affects the functionality of the code. &lt;/li&gt;
&lt;li&gt;Code readability is also very important. Following the organization standard, providing comments where necessary, is required. &lt;/li&gt;
&lt;li&gt;Don't spam the channel if you don't get a reply immediately. Be patient and wait for the appropriate amount of time before asking again. &lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;So it was the end of a general contribution guide for opensource. Let's take a deep dive into how we tackled our problems and some tips with Facebook's Jest project&lt;/p&gt;



&lt;h2&gt;
  
  
  New Feature: &lt;strong&gt;Reporting individual tests&lt;/strong&gt;
&lt;/h2&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/facebook/jest/pull/10227" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        feat: report Individual Test Cases
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#10227&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/sauravhiremath" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--qVh9sXUx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars1.githubusercontent.com/u/28642011%3Fv%3D4" alt="sauravhiremath avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/sauravhiremath" rel="noopener noreferrer"&gt;sauravhiremath&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/facebook/jest/pull/10227" rel="noopener noreferrer"&gt;&lt;time&gt;Jul 02, 2020&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Summary ⚡
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[&lt;strong&gt;Part 2&lt;/strong&gt; of 2] - Depends on #10293&lt;/li&gt;
&lt;li&gt;Initially jest runs would update &lt;code&gt;testSuites&lt;/code&gt; incrementally, and update individual test cases batch-wise. This PR attempts to report the progress of the individual (atomic) test-cases.&lt;/li&gt;
&lt;li&gt;Supported for Jest-Circus Runner.&lt;/li&gt;
&lt;li&gt;Introduces &lt;code&gt;eventListeners&lt;/code&gt; for the worker processes to send back the test results to their parent.&lt;/li&gt;
&lt;li&gt;Handles progress reports both when running tests parallelly (spawning workers) and inBand (Sequentially).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Previous References and suggestions&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Fixes: &lt;a href="https://github.com/facebook/jest/issues/6616" rel="noopener noreferrer"&gt;https://github.com/facebook/jest/issues/6616&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Reference: &lt;a href="https://github.com/facebook/jest/pull/9001" rel="noopener noreferrer"&gt;https://github.com/facebook/jest/pull/9001&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Test plan ⚡
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[x] Add custom message support in jest-worker&lt;/li&gt;
&lt;li&gt;[x] Update &lt;code&gt;onCustomMessage&lt;/code&gt; functions to pass tests (caused by updating its Type)
API implemented as suggested here - &lt;a href="https://github.com/facebook/jest/issues/6616#issuecomment-402782271" rel="noopener noreferrer"&gt;https://github.com/facebook/jest/issues/6616#issuecomment-402782271&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[x] Fix the memory leak issue&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Current Implementation&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://camo.githubusercontent.com/441536bc56012816089d002b098bc8cf5c3e6a83/68747470733a2f2f6d656469612e67697068792e636f6d2f6d656469612f56686274355138436461536a31736b3733492f736f757263652e676966" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/441536bc56012816089d002b098bc8cf5c3e6a83/68747470733a2f2f6d656469612e67697068792e636f6d2f6d656469612f56686274355138436461536a31736b3733492f736f757263652e676966" alt="implementation-demo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Authors&lt;/h2&gt;
&lt;p&gt;Co-author - Saurav M. H @sauravhiremath
Co-author - Kunal Kushwaha @kunal-kushwaha
Co-author - Rogelio Guzman @rogeliog&lt;/p&gt;
&lt;h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;@kunal-kushwaha for his super awesome contribution  🚀  🚀
@rogeliog for laying down the foundation for this PR. 🚀
@SimenB and &lt;a class="mentioned-user" href="https://dev.to/jevakallio"&gt;@jevakallio&lt;/a&gt; for their time and reviews 👏&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/facebook/jest/pull/10227" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Sometimes for bringing in a new feature you will have to go through the majority of the child repos and may get overwhelming. It is pretty normal for monorepo projects. In this case, make a rough chart or flow diagram so you know what you are doing and not get lost in the huge project.&lt;/li&gt;
&lt;li&gt;Okay okay, we had one tiny advantage here. The problem was already discovered. I cannot stress enough how much a well-defined problem is equally important as compared to its devised solution.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The problem:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;It seems like Jest currently only reports progress when a complete suite passes. We propose that instead, it should report progress every second for individual test cases. (well we made it much better than per-second, more on it later)&lt;/li&gt;
&lt;li&gt;Otherwise, the progress output is confusing. "Tests: N" being a separate line in the output gives the impression that it's just as granular as "Test Suites: N" and will be incremented immediately when a test case passes.&lt;/li&gt;
&lt;li&gt;So the problem text alone can be confusing. And you bet just reading the above statement is not enough. So, here comes an explanatory image&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc7s2ww13eu5hmo5wco72.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc7s2ww13eu5hmo5wco72.gif" alt="problem-gif" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The solution
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Breaking the issue into separate features
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Support sending Custom Messages to the parent from a worker thread&lt;/li&gt;
&lt;li&gt;Report the progress for individual test cases&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Support sending Custom Messages to the parent from worker threads
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;It adds the &lt;code&gt;jest-worker&lt;/code&gt; ability for workers to send "custom messages" to their parent while they are still running. This will eventually allow us to report per test case updates to the reporter.&lt;/li&gt;
&lt;li&gt;This part was particularly tricky, as there were some legacy code which was very confusing to work with (pretty common with huge codebases)&lt;/li&gt;
&lt;li&gt;Leveraged the introduction of eventEmitters in Nodev10 (used &lt;code&gt;emittery&lt;/code&gt; which is a typed form of node eventEmitters) to send the messages instead of using the traditional callbacks.&lt;/li&gt;
&lt;li&gt;The emitter was used only for parallel runs (supporting worker threads). For in-band runs, there wasn’t much modification needed.&lt;/li&gt;
&lt;li&gt;Modifying a major chunk of the &lt;code&gt;jest-worker&lt;/code&gt; module, this PR was landed without any breaking change.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Report the progress for individual test cases
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The proposed feature:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Initially, jest runs would update testSuites incrementally, and update individual test cases batch-wise. This PR attempts to report the progress of the individual (atomic) test-cases.&lt;/li&gt;
&lt;li&gt;Supported only for &lt;code&gt;jest-circus&lt;/code&gt; runner.&lt;/li&gt;
&lt;li&gt;Introduces eventListeners for the worker processes to send back the test results to their parent using &lt;code&gt;emittery&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Handles progress reports both when running tests parallelly (spawning workers) and inBand (Sequentially).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Again the proposal is incomplete without a demonstration for it
&lt;img src="https://camo.githubusercontent.com/441536bc56012816089d002b098bc8cf5c3e6a83/68747470733a2f2f6d656469612e67697068792e636f6d2f6d656469612f56686274355138436461536a31736b3733492f736f757263652e676966" alt="proposed-feature-demo" width="" height=""&gt;
&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  Finding bugs is a learning opportunity - The Memory Leak
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;How did we find it?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Thankfully there was a memory leak test inside jest. Essentially it created a shallow copy of the objects and then deleted all the references (or edges) to this node. (I refer to the node here in global object heap context.) If the object was still not garbage collected then it means there is a memory leak because there are still other objects referencing it. This is essentially how memory leak is detected. Fortunately, we don’t have to code this manually, someone has already built an npm module for it.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;What we tried and for how long?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Oh boy! This was the most tiresome part. Knowing how the memory leak worked was not enough to debug this. At first, we tried manually finding any naive mistakes in the codebase, but it was of no avail.&lt;/li&gt;
&lt;li&gt;Next thing, we took the memory snapshots at various intervals while running tests. Here we run the tests inBand, so it's easier to understand where things are going wrong. &lt;/li&gt;
&lt;li&gt;Then we profiled these snaps and tried finding useful information here. No luck here too. &lt;/li&gt;
&lt;li&gt;Did a heap memory log of the tests, but nothing out of the blue here too.&lt;/li&gt;
&lt;li&gt;Now, we used the oldest recipe in the cookbook, as recommended by the master chefs. NUKING THE CODES! (kudos to &lt;a href="https://twitter.com/taneliang" rel="noopener noreferrer"&gt;@taneliang&lt;/a&gt; for finding this hidden recipe)&lt;/li&gt;
&lt;li&gt;We started removing chunks of codes, to see if which part was causing the issue. This was our last resort and we started with the place we thought was most vulnerable to the memory leak. &lt;strong&gt;And, VOILA! We found it&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;How did we fix it?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We found it was due to a direct reference for the object being sent to the worker thread. And even after the worker process was orphaned, it still held the object reference with it. So, we solved this by creating a deepCyclicCopy (which is a fancy way of saying we did a deep copy of an object which may or may not have cyclic references) and sent it to the worker threads again. And yes, it worked!&lt;/li&gt;
&lt;li&gt;It was a one-line fix. JUST ONE LINE!
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;sendMessageToJest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eventEmitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nf"&gt;deepCyclicCopy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;keepPrototype&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6g1mly80vstu6zlr8r34.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6g1mly80vstu6zlr8r34.gif" alt="oh-no" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What did we learn?&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;But, coming to this one line was one of the best journeys we had. We learned a lot about 

&lt;ul&gt;
&lt;li&gt;Chrome v8 heaps. &lt;/li&gt;
&lt;li&gt;How the garbage collection is handled internally.&lt;/li&gt;
&lt;li&gt;How does Node maintain different heaps and inter-references between the worker thread it spawns. &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;These were some of the things we learned when fixing this bug. &lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;h1&gt;
  
  
  So, concluding it…
&lt;/h1&gt;

&lt;p&gt;Yay! You survived the nerd blog. Here, have a cookie 🍪&lt;/p&gt;

&lt;p&gt;Also, We are no experts here and neither is our work perfect. Just some fellows sharing their experience. You may agree or not agree with some of our points here. And it’s completely fine, we respect you for questioning our work. This is just a roadmap we took and laid, you may either tread this path or find your own. Both have their fun and hurdles :)&lt;/p&gt;

&lt;p&gt;So that was about it. That’s how we started with a project we had never contributed to before and landed a new feature during the Fellowship. A huge shout out to all the community members, MLH fellowship team, &amp;amp; everyone else for being a part of this journey and empowering everyone to achieve more.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Thanks for reading.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fh1ykyaz3l3aplzo9xdvt.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fh1ykyaz3l3aplzo9xdvt.jpg" alt="May the source be with you" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  About the Authors
&lt;/h3&gt;

&lt;h4&gt;
  
  
  About Kunal:
&lt;/h4&gt;

&lt;p&gt;Hello everybody! My name is Kunal and I am a junior from India. My interests include DevOps, Machine Learning, and Web Development. I have been a part of various open-source programs like the MLH Fellowship, Google Summer of Code, Google Code-I, etc. Outside of work, I am a core team member of various college societies and programming boot camps where I teach students Data Science and DevOps. I also volunteer at a community (codecau.se/yt) which I started, as an instructor, &amp;amp; have thousands of students learning with us.&lt;br&gt;
I have been contributing to open-source since my freshman year and it has made a lasting impact on my career journey. My goals include working on products &amp;amp; services that have an impact on the world. Hence, I would love to work for an organization that’s leading the future of the industry.&lt;/p&gt;

&lt;h4&gt;
  
  
  About Saurav:
&lt;/h4&gt;

&lt;p&gt;A friendly neighborhood developer from India :D A computer Science Engineering student doing specialization in Bioinformatics. Absolutely love working on DevOps and Full Stack Web Development. Have experience working on product and platform architectures for startups. Have been part of Technical Chapters and delivered Talks on Deep Learning and Product Deployments. Keen believer of open source community. Currently part of MLH Fellowship and been an OSS contributor for 2 years.&lt;br&gt;
My work was and always will be driven towards making people’s life easier and building products that create a difference. To sum it up, I love my Arch and OpenSource :)&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>mlhgrad</category>
      <category>javascript</category>
      <category>career</category>
    </item>
    <item>
      <title>Building a multiplayer game using WebSockets - Part 1</title>
      <dc:creator>Saurav M H</dc:creator>
      <pubDate>Mon, 06 Jul 2020 20:00:53 +0000</pubDate>
      <link>https://dev.to/sauravmh/building-a-multiplayer-game-using-websockets-1n63</link>
      <guid>https://dev.to/sauravmh/building-a-multiplayer-game-using-websockets-1n63</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;A definitive guide for building your multiplayer game on a browser the right way using socket.io on NodeJS and React. Ranging from folder-structure to project deployments&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Getting started with a unique idea is important. But it is much more crucial to set the foot in the right direction when starting with a project.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The future belongs to those who learn more skills and combine them in creative ways."&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Robert Greene, Mastery&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why another tutorial?
&lt;/h2&gt;

&lt;p&gt;This is very important to clarify. There are tons of guides online focusing on “Getting started with socket.io” and it gets more frustrating when all of them are chat apps. But here we will focus on “Getting started with building a scalable project using Socket.io”, which is not a chat app :).&lt;/p&gt;

&lt;p&gt;This guide will explain more about the Code Infrastructure rather than focusing on UI/UX. So bear with me if UI doesn’t look so appealing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is socket.io?
&lt;/h2&gt;

&lt;p&gt;Socket.io is an abstraction built over the WebSockets protocol. Websockets is a protocol that allows a bilateral synchronous exchange between a client and a server. Or a bi-directional communication pipe in simple words&lt;br&gt;
Note: Here WebSockets and socket.io will be used interchangeably (even though they are different in some aspects) unless stated otherwise.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why WebSockets and not HTTP?
&lt;/h2&gt;

&lt;p&gt;For real-time multiplayer games, we require the client to send information packets to the server and server sending/broadcasting data simultaneously. This can’t be achieved using HTTP as the client has to send a request to the server to actually receive something. This isn’t a viable scenario for multiplayer games.&lt;/p&gt;
&lt;h2&gt;
  
  
  What do you mean by the “Right way”?
&lt;/h2&gt;

&lt;p&gt;The Right way — here means getting started with a Codebase which can be easily scaled further, and simultaneously not creating much hassle for smaller projects. It addresses common practices that can be followed for a much more modular project. This in no manner states it is the official way to build WebSockets projects. But is simply my opinion on it, you can easily swap out bits and parts of the project you don’t like :D&lt;/p&gt;
&lt;h2&gt;
  
  
  What is the project about? ⚡⚡
&lt;/h2&gt;

&lt;p&gt;So coming to the core of the guide. This guide explains building a “multiplayer socket.io game” through a real-world project. This way it is much easier to see the project in action and we know the code/infrastructure works too! The project is…&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Multiplayer Football Draft Simulator&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  What does this game do? ⚡
&lt;/h3&gt;

&lt;p&gt;It is a turn-based multiplayer game. Where people enter and create a room. Other people hop into the room. Then the game begins where all players are shuffled and first-person gets the chance to pick the football-player he wants. He can search from the list of players (viewing their stats, position, ratings, and other details) and confirm his selection within the allocation time. Now, the turn is passed to another player. This repeats until every person has picked their whole football squad.&lt;/p&gt;

&lt;p&gt;Pretty simple? Yes/no, it doesn’t matter. We will see the detailed breakdown of the code infrastructure behind this.&lt;/p&gt;
&lt;h2&gt;
  
  
  Server Architecture ⚡⚡⚡
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0cbltnn2xt0aoqhphe3c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0cbltnn2xt0aoqhphe3c.png" alt="Game-architecture"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Game architecture
&lt;/h2&gt;

&lt;p&gt;The above diagram explains how everything is connected from a birds-eye point of view.&lt;/p&gt;

&lt;p&gt;Both the HTTP and Websockets server in this guide uses NodeJS. We are using Redis DB as socket.io supports its integration out of the box also the read/write operations are much faster as data is stored in-memory. MongoDB is used as a more permanent storage solution. The game results and the user teams for each room are stored in MongoDB after the end of each draft round. It also stores user credentials if they wish to register (this project has an optional registration/login step).&lt;/p&gt;

&lt;p&gt;The WebCrawler is written in Python3, using the Scrapy library. The football players dataset has been crawled from &lt;a href="https://sofifa.com" rel="noopener noreferrer"&gt;https://sofifa.com&lt;/a&gt;. It consists of more than 20,000 players including their rating, statistics, worth, clubs, etc. It also has an optional data-analysis jupyter-notebook for playing with the scraped data, but its discussion is out of scope for this guide.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Folder Structure (ExpressJS + MongoDB + socket.io)
&lt;/h3&gt;

&lt;p&gt;NodeJS does not enforce code structure on you. This gives us a lot of flexibility to design them, but you can go horribly wrong which can lead to difficulty in maintaining and scaling the projects. This particular project structure can be used when working with sockets + NodeJS&lt;/p&gt;

&lt;p&gt;Let's dive in how the project codebase is structured&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.{src}  
├── controller  
│   ├── authController.js      # Handles authentication requests  
│   ├── searchController.js    # Handles search queries  
│   ├── userController.js      # Handles user profile operations  
│   └── ...  
│  
├── database  
│   ├── db.js                  # Initialize DB connection  
│   └── ...  
│  
├── middlewares  
│   ├── authenticated.js       # Decode and verify JWT token  
│   ├── error.js               # Common Error Handler  
│   ├── logger.js              # Control logging levels  
│   └── ...  
│  
├── models  
│   ├── roomsModels.js         # DB model for rooms  
│   ├── usersModel.js          # DB model for users  
│   └── ...  
│  
├── schema  
│   ├── rooms.js               # DB Schema for rooms  
│   ├── users.js               # DB Schema for users  
│   └── ...  
│  
├── socker  
│   ├── roomManager.js         # Socket listeners/emitters handle  
│   ├── sockerController.js    # Control socket connections  
│   └── ...  
│  
├── app.js                     # Entry file for the project  
├── env.js                     # Store environment variables  
├── routes.js                  # All routes initializer  
└── ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;The backend is divided into different directories according to the project requirement. If you want to skip or swap certain modules, it is as easy as adding another directory.&lt;/p&gt;

&lt;p&gt;Most of the sub-directories are common to node projects, so I won't explain them in detail here. The comments beside each directory should give an idea of what it is.&lt;/p&gt;

&lt;p&gt;We will focus more on &lt;strong&gt;subdirectory socker/&lt;/strong&gt;. This the place where your core socket.io code will reside.&lt;/p&gt;
&lt;h3&gt;
  
  
  The entry point for socket.io (App.js)
&lt;/h3&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Here two servers are created, &lt;code&gt;app&lt;/code&gt; — listening to HTTP requests and &lt;code&gt;server&lt;/code&gt; — listening to WebSockets connections. It is recommended to keep them connected to different PORTs to avoid confusion.&lt;/p&gt;

&lt;p&gt;You might be wondering what is "socker" on line 1 and 8.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is socker?
&lt;/h2&gt;

&lt;p&gt;Socker is just a function alias (because I am building a football draft game here, duh!). This function attaches the &lt;code&gt;Server&lt;/code&gt; (passed in line 8 of app.js) to an engine.io instance on a new &lt;code&gt;http.Server&lt;/code&gt;. In simple words, it attaches the socket.io engine to the server passed to it.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;But the above code doesn't explain much. Now, the following questions arise:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How do I interact with connected clients?&lt;/li&gt;
&lt;li&gt;Where are namespaces?&lt;/li&gt;
&lt;li&gt;Where are the Rooms/Channels?&lt;/li&gt;
&lt;li&gt;Most importantly, where is the game?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Creation of Namespaces and why?
&lt;/h2&gt;

&lt;p&gt;Namespaces are an important feature of socket.io. It represents a pool of sockets connected under a given scope identified by a pathname like &lt;code&gt;/classic-mode&lt;/code&gt; , &lt;code&gt;/football-draft&lt;/code&gt; , &lt;code&gt;/pokemon-draft&lt;/code&gt; , etc. This is basically creating different endpoints or paths. It allows us to minimize the number of resources (TCP connections) and at the same time separate concerns within your application by introducing a separation between communication channels. By default, socket.io connects to the&lt;code&gt;/&lt;/code&gt; namespace.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creation of Rooms/Channels and why?
&lt;/h2&gt;

&lt;p&gt;Within each namespace, you can create arbitrary channels or rooms. This further allows you to create connections which sockets can &lt;code&gt;join&lt;/code&gt; or &lt;code&gt;leave&lt;/code&gt; . Here we use &lt;code&gt;channels&lt;/code&gt; to create different rooms where users can join or create to play together.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example of joining a room&lt;/em&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;join()&lt;/code&gt; operation checks if the required &lt;code&gt;roomId&lt;/code&gt; is already created. If not, then it creates the room and adds the player to the given roomId. And if it is already created it joins the room directly.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A wholesome example summarizing the use of namespaces and channels:&lt;/em&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;That's it for Part I. The code structure shown here works for medium size projects quite well. If you are building a quick prototype, you may omit or combine the schema and models folder. Do not hesitate to make the project lighter if required :)&lt;/p&gt;

&lt;p&gt;What if the project size increases? The current structure might not work well. You can create sub-folders as per required services and components ( &lt;code&gt;user-authentication&lt;/code&gt; , &lt;code&gt;__tests__&lt;/code&gt; , &lt;code&gt;analytics&lt;/code&gt; , etc.). You might even create microservices i.e. deploying each process or service individually allowing you to load-balance or scale only the processes under heavy-loads.&lt;/p&gt;

&lt;p&gt;Remember do not over-engineer your product, build and deploy in stages!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff6kn4uqqai1jsgzwbcxu.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff6kn4uqqai1jsgzwbcxu.jpeg" alt="joke"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Be it a joke or an engineering-project, no one likes overdoing it :)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you are interested, here are my project links:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Backend (Websockets + HTTP) - &lt;a href="https://github.com/sauravhiremath/fifa-api" rel="noopener noreferrer"&gt;https://github.com/sauravhiremath/fifa-api&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Frontend (ReactJS) -  &lt;a href="https://github.com/sauravhiremath/fifa" rel="noopener noreferrer"&gt;https://github.com/sauravhiremath/fifa&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;WebCrawler (Python3 + Scrapy) - &lt;a href="https://github.com/sauravhiremath/fifa-stats-crawler" rel="noopener noreferrer"&gt;https://github.com/sauravhiremath/fifa-stats-crawler&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Next article/articles will focus on:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creation and handling of rooms for each namespace.&lt;/li&gt;
&lt;li&gt;A brief explanation of the client-side of the project (in ReactJS)&lt;/li&gt;
&lt;li&gt;CI and Deployment of each project package.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Let me know if you have any questions or suggestions for future articled&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;✌️&lt;strong&gt;&lt;em&gt;️ Have a great day!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Follow me on twitter @&lt;a href="https://twitter.com/sauravmh" rel="noopener noreferrer"&gt;sauravmh&lt;/a&gt; for updates!&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>webdev</category>
      <category>node</category>
    </item>
  </channel>
</rss>
