Rabikant

Posted on March 9th

Building a Secure WebSocket Server in Node.js and Securing it with Apache

"Let's build a Secure WebSocket Server in Node.js and Securing it with Apache"

Apache historically has been referred to as the Apache HTTP Server, and it remains among the most popular web servers developed as open-source software. Established and supported by the Apache Software Foundation, it has been instrumental in us being able to use the Web as it is today since it was first released in 1995. Apache is a potent, versatile, and stable software to deliver Web content over the World Wide Web.

Key Features of Apache

  1. Open Source and Free: Apache is open source software that uses Apache License 2.0, so it can be used, modified and distributed free of charge. This has helped in its deployment as well as constant upgrade by many developers across the world.
  2. Cross-Platform: Apache supports concurrent users, systems, and platforms; it works on Linux, Windows, Mac OS X, and other Unix like operating systems. However, the usage of regex is most preferred on Linux operated systems.
  3. Modularity: Apache server is highly flexible because of its modular design. Apache also has its core server, it is used with a module that add more functionality to the server. For example:The structure of Apache is one of its greatest assets Apache is built as a set of sub-modules called module. Apache distributions has a main server yet it has provision for extension through modules that enhance its capabilities. For example: mod_ssl for managing SSL/TLS connections securely for web servers. mod_rewrite which helps to rewrite URLs as well as is used for redirection which is valuable for the URL structure of the website. mod_proxy to make Apache work as reverse-proxy or forward request to other applications like a websocket application server or backend application server.
  4. Performance and Scalability: Apache can be used for simple websites and for big Internet projects with thousands of users visits per day. Apache comes with the support of many MPMs that determine how this web server handles numerous connections simultaneously. Depending on the preferences, one can select which of the options will allow delivering requests with efficiency.
  5. Customization and Flexibility: Apache is completely configurable to the requirements. It is configured by making changes in text files; for instance, httpd.conf is a common file administrational modifying to be able to control and manage how the server works. From the control of multiple hosts simultaneous to the possibility to change the standard error messages Apache is very versatile.

How Does Apache Work?

Apache is the software through which, whenever a web browser communicates a web page via URL or link, the request made by a web browser is processed and the corresponding web content is provided. Apache follows a request-response cycle:

  1. The client (web browser) forms a request to the server using the hypertext transfer protocol that is HTTP request.
  2. Apache gets the request, interprets it and reads what it has to send back (a file, data generated dynamically in a backend engine, etc.).
  3. Apache returns the content to the client side and it will be displayed in the browser.

Apache can also be used with other technologies such as PHP, Python, and Perl, which makes Apache to be widely used in creation of dynamic content.

What are WebSockets?

Before I go any further with the configuration, let me take few words to introduce the readers with WebSockets. WebSockets are long connection associated with server and client while HTTP is-sessionless Real-time Real protocol. WebSockets is a long standing connection where the server is able to send information down to the client without the client making request for the information.

In the context of modern web applications, WebSockets are used for real-time functionalities such as: The usage of social media such as live chat and messages. Web applications employed during collaboration – especially if the collaboration is being done online like Google docs.

Real time feeds of and trading floors of the relevant financial markets

  • Multiplayer games and more

But availability and usage and variations and operations of WebSockets has to be protected by several factors such as the information. That is where the next server comes to rescue it as reverse proxy to ensure the safety of the Websocket connections.

Step 1: WebSocket Server Implementation in Node.js: 

We will create a WebSocket server using one of the most frequently used packages – ws. So let’s do it in steps:

1.1 Requirements & Setup

For this basic example to run you should install Node.js server-side JavaScript on your system. In addition to this, the basic example uses the websocket library ws. ″

First, if you don’t have Node.js installed, download and install it from the Node.js official website. Afterward, initialize a Node.js project and install the ws WebSocket package:

mkdir websocket-server
cd websocket-server
npm init -y
npm install ws

1.2 Create the WebSocket Server (server.js)

Now, create a server.js file, which will serve as our WebSocket server. Here’s the code to set up a simple WebSocket server that listens for incoming connections and messages:

const WebSocket = require('ws');

// Create WebSocket Server on port 8080
const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', (ws) => {
  console.log('New client connected');

  // When the server receives a message from the client
  ws.on('message', (message) => {
    console.log('Received:', message);

    // Respond to the client
    ws.send('Server received: ' + message);
  });

  // Handle client disconnection
  ws.on('close', () => {
    console.log('Client disconnected');
  });
});

console.log('WebSocket server is running on ws://localhost:8080');

This basic server listens on port 8080 for WebSocket connections. When a client connects and sends a message, the server echoes back a confirmation message.

1.3 Running the Server

To run the WebSocket server, use t=he following command:

node server.js

Your WebSocket server is now running and ready to accept connections!

Step 2: Creating the WebSocket Client

Next, we need a client to connect to our server and send messages.

2.1 Create the WebSocket Client (client.js)

In the same project folder, create a client.js file. This will connect to the WebSocket server and allow you to interact with it.

const WebSocket = require('ws');
const readline = require('readline');

// Create WebSocket connection
const socket = new WebSocket('ws://localhost:8080');

// Setup readline interface for user input
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

// When the connection is open
socket.on('open', () => {
  console.log('Connected to server');

  // Prompt for input after connection
  rl.question('Enter message to send: ', (message) => {
    socket.send(message);
  });
});

// Handle incoming messages from the server
socket.on('message', (message) => {
  console.log('Message from server:', message);

  // Prompt for the next message after receiving a response
  rl.question('Enter message to send: ', (message) => {
    socket.send(message);
  });
});

// Handle connection closure
socket.on('close', () => {
  console.log('Connection closed');
  rl.close();
});

This client connects to the server at ws://localhost:8080, and prompts you to enter a message, which is then sent to the server. It also listens for responses from the server.

2.2 Running the Client

Once your server is running, open a new terminal window or tab and run the client:

node client.js

You should now see a prompt to enter a message, and after sending the message, the server will echo a response.

Step 3: Securing the WebSocket with Apache

Running a WebSocket server on plain ws:// is fine for development, but for production, you need to secure the communication with SSL/TLS. We’ll achieve this by setting up Apache as a reverse proxy and securing it with HTTPS.

3.1 Install Apache and Enable Modules

Make sure Apache is installed on your system. If not, install it with:

sudo apt install apache2

Then, enable the necessary modules for proxying WebSockets and handling SSL:

sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel
sudo a2enmod ssl

3.2 Obtain SSL Certificates

You can either:

  • Use Let’s Encrypt for free SSL certificates (recommended for public domains).
  • Use your own certificates.

To install a free Let’s Encrypt certificate, run:

sudo apt install certbot python3-certbot-apache
sudo certbot --apache -d yourdomain.com

3.3 Configure Apache for WebSocket Reverse Proxy

Edit your Apache virtual host file (/etc/apache2/sites-available/yourdomain.com.conf). Here’s a sample configuration for proxying WebSocket traffic and enabling SSL:

<VirtualHost *:443>
    ServerName yourdomain.com

    # Enable SSL
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/yourdomain.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/yourdomain.com/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf

    # Proxy WebSocket connections
    ProxyPass "/ws" "ws://localhost:8080/"
    ProxyPassReverse "/ws" "ws://localhost:8080/"

    # Optional: Proxy HTTP connections if needed
    ProxyPass "/" "<http://localhost:8080/>"
    ProxyPassReverse "/" "<http://localhost:8080/>"

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

<VirtualHost *:80>
    ServerName yourdomain.com

    # Redirect HTTP to HTTPS
    Redirect permanent / <https://yourdomain.com/>
</VirtualHost>
  • The ProxyPass and ProxyPassReverse directives forward WebSocket traffic (ws://) from Apache to your WebSocket server running on port 8080.
  • The SSLEngine on enables SSL/TLS on your domain.

3.4 Enable the Site and Restart Apache

After making changes, enable the site and restart Apache:

sudo a2ensite yourdomain.com.conf
sudo systemctl restart apache2

3.5 Update the WebSocket Client for Secure Communication

Finally, update your WebSocket client to connect securely using wss:// instead of ws://. In client.js, change the connection URL:

const socket = new WebSocket('wss://yourdomain.com/ws');

Your WebSocket connection is now encrypted with SSL, and Apache is handling the secure reverse proxying.

Complete Code

The project is available on our GitHub : https://github.com/piehostHQ/node-secure-websocket

Comments

Leave a comment.

Share your thoughts or ask a question to be added in the loop.