DEV Community

Mark Voorberg
Mark Voorberg

Posted on • Updated on

Socket.io with Apache on a CPanel VPS

I've been running Node.js apps on my WHM/CPanel VPS for a little over a year now and proxying web requests through Apache has been working pretty well.

However, with my latest project, I'm using Socket.io to send messages to the front-end in real-time. I had everything working locally, but after deploying both the API and my front-end, the websockets were unable to connect.

After a bit of reading, it became clear that I need to use ProxyPass which isn't allowed in a .htaccess file. On a typical deployment you'd add it to a configuration file under the sites-available folder, but with WHM/CPanel, that option just isn't there.

On a cPanel/WHM server, the Apache configuration file is an httpd.conf that gets re-generated each time changes are made, so it's really not recommended to make changes to it manually.

Here's the notice at the bottom of the file:

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
#   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#   DO NOT EDIT. AUTOMATICALLY GENERATED.  USE INCLUDE FILES IF YOU NEED TO MAKE A CHANGE
#   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

That doesn't mean we can't override to the VirtualHost settings, we just need to make our changes in an include file.

Have a look at your httpd.conf by printing it to the terminal with:

$ cat /etc/httpd/conf/httpd.conf

Note the following lines after each VirtualHost, where myuser and mydomain.net match your CPanel account.

# To customize this VirtualHost use an include file at the following location
# Include "/etc/apache2/conf.d/userdata/ssl/2_4/myuser/api.mydomain.net/*.conf"

Notice that the path above includes ".../ssl/...".
There's a corresponding ".../std/..." for services that
don't require a secure connection. I won't recommend
running any services without SSL, so I didn't even look
at that configuration.

The folder listed above won't likely exist yet, but you can create it with:

$ mkdir -p /etc/apache2/conf.d/userdata/ssl/2_4/myuser/api.mydomain.net

Then create a new config file with:

$ cd /etc/apache2/conf.d/userdata/ssl/2_4/myuser/api.mydomain.net
$ touch custom.conf
$ nano custom.conf

The contents of the custom configuration will vary based on your need, but in my case, I needed to connect to a socket host running on port 7222 on the api.mydomain.net subdomain. The same subdomain also hosts my Node.js REST api, so I needed to split out the websocket traffic and upgrade it as needed.

FYI: I wasted a lot of time editing my custom.conf file in the domain root ".../myuser/mydomain.net", where it should have been in the folder that corresponds to my subdomain ".../myuser/api.mydomain.net".
It was a huge waste of time as I fiddled with settings that were not applied to the subdomain where I was testing my application. If you're making edits that don't appear to have any effect, confirm that your config file is in the folder for the domain you're testing against.

In broad strokes, I need to proxy any websocket traffic to localhost:7222. The contents of my custom.conf file is as follows:

ProxyPreserveHost On
RewriteEngine On

# Upgrade connections to WebSockets
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule /(.*) ws://localhost:7222/$1 [P,L]

# Redirect http to https
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

# Everything else forwards as HTTP to the node app.
ProxyPass / http://127.0.0.1:7222/
ProxyPassReverse / http://127.0.0.1:7222/

Once I felt that the rules were correct I saved the file and ran:

$ /scripts/verify_vhost_includes
> Testing
> /etc/apache2/conf.d/userdata/ssl/2_4/myuser/api.mydomain.net/custom.conf...ok

This confirmed that my changes weren't broken so badly that they'd prevent Apache from trying to load them. If that were to happen, and I didn't test it first, I could potentially prevent other websites on my host from being served.

This is only one of two VirtualHosts with a custom config file on my machine so I was happy to make sure we use all the existing include files:

$ /scripts/ensure_vhost_includes --all-users
> Built /etc/apache2/conf/httpd.conf OK

Alternatively, I could have used the following CPanel script to ensure that my httpd.conf contained the necessary Include statements.

$ /usr/local/cpanel/scripts/rebuildhttpdconf
> Built /etc/apache2/conf/httpd.conf OK

The only remaining step was to bounce Apache & test out my new VirtualHost Rewrite & ProxyPass rules.

To restart Apache, run the following:

$ /scripts/restartsrv_httpd

This should do a soft restart, which simply means that it will restart after it finishes serving any active connections.

After making these changes, my Angular app socket service was able to successfully connect to a Node.js app running behind my Apache webserver.

Top comments (2)

Collapse
 
fadelhmd profile image
Fadel

hello@Mark Voorberg in my case im using shared hosting cpanel so i dont have a terminal or Apache configuration and when im settinh the .htaccess in public_html i get the error from socket.io in network : you have to enable javascript any help?

Collapse
 
4umfreak profile image
Mark Voorberg

Without root access to the machine, I'm doubtful that you can make the necessary changes. These settings get baked into the apache config which, in your case, will shared with other users on the box.
Javascript will have nothing to do with it.