How To Deploy A Production Ready Websockets Server In 5mins

In this post, we will look at how to quickly set up and deploy a production-grade WebSocket server. We use python/Django in the examples but this can be applied to any language supported by the pusher SDK.

We will use Soketi, an open-source, fast WebSockets server that implements the pusher protocol. Pusher is a hosted service that makes it easy to build real-time applications, they provide SDKs for most languages.

Prerequisites

  • Docker - for local testing and packaging of the app for deployment 
  • Fly.io - optional - fly.io account and flyctl cli application.

Run a local server

Run the command below to start a local server. We will look at some examples of how you can test later in the article.

docker run -p 6001:6001 -p 9601:9601 quay.io/soketi/soketi:1.0-16-debian

Status: Downloaded newer image for quay.io/soketi/soketi:1.0-16-debian

  🕵️‍♂️ Initiating metrics endpoints...  

   🎉 Server is up and running!   
   📡 The Websockets server is available at 127.0.0.1:6001   
   🔗 The HTTP API server is available at http://127.0.0.1:6001   
   🎊 The /usage endpoint is available on port 9601.   


Package

Dockerfile

FROM quay.io/soketi/soketi:1.0-16-debian

ENV SOKETI_DEBUG=0
ENV SOKETI_DEFAULT_APP_KEY='PUSHER_KEY'
ENV SOKETI_DEFAULT_APP_ID='4712912'
ENV SOKETI_DEFAULT_APP_SECRET='PUSHER_SECREY'

Notes

ENV - set up the environment variables for your server. Remember to keep your APP_SECRET secure!

Deploy

This is optional. In this example, we are deploying our container to fly.io. You can also deploy to any cloud provider. If you haven't already, follow the instructions here to sign up for a free account and install the flyctl cli. They have a free tier, credit cards are not required.

Run the following in a terminal from the same folder as your Dockerfile.

$ flyctl launch

Scanning source code
Detected a Dockerfile app
> ? App Name (leave blank to use an auto-generated name): soketi

? Select region: ams (Amsterdam, Netherlands)
? Would you like to set up a Postgresql database now? No
? Would you like to deploy now? No

Your app is ready. Deploy with `flyctl deploy`

Notes

flyctl launch - this will create a fly.toml configuration file for your application.

fly.toml

kill_signal = "SIGINT"
kill_timeout = 5
processes = []

[env]

[experimental]
  allowed_public_ports = []
  auto_rollback = true

[[services]]
  http_checks = []
  internal_port = 6001 --> make sure this set to the correct port
  processes = ["app"]
  ...

Notes

  • internal_port - by default, fly expects your service to listen to requests on port 8080. Change this to port 6001.

Finally, deploy the application

$ flyctl deploy

Remote builder fly-builder-nameless-field-1262 ready
==> Creating build contextWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW 
......
==> Monitoring deployment

 1 desired, 1 placed, 1 healthy, 0 unhealthy [health checks: 1 total, 1 passing]
--> v0 deployed successfully

# check the deployment

$ flyctl info

App
  Name     = soketi          
  Owner    = personal            
  Version  = 0                   
  Status   = running             
  Hostname = soketi.fly.dev  


The image will be built remotely and pushed to the platform. Run flyctl info to get the status and information about your service. This will also provide the Hostname.

Are you building a SaaS product and want to launch like ASAP? Check out the Vanty Starter Kit. Our Django boilerplate has everything you need to launch your app today!

Learn more →

Examples

Let's look at a simple example of how to trigger events and subscribe to channels.

Triggering an event

In the example below we will trigger an event from a backend server using the python pusher library. Install the pusher library:

pip install pusher

realtime.py

# run pip install pusher
import pusher

def realtime_client() -> Pusher:
    return pusher.Pusher(
        app_id='471292',
        key=PUSHER_KEY,
        secret=PUSHER_SECRET,
        host='soketi.fly.dev',
        port=443,
        ssl=True,
    )

service.py

def promo_service(channel="promotions", event='summer-promo'):
    data = {"message":"launch-today with the vanty starter kit"}
    realtime_client().trigger(channel, event, data)  

Notes

  • realtime_client() - a client that returns an instance of the Pusher class.
  • promo_service - a fake service that will push events to the promotions. In this case, the event has some data attached to it.

Subscribing to a channel

In the example below we will subscribe to and listen to any events from the promotions channel.

# html
<script defer src="https://js.pusher.com/7.2/pusher.min.js"></script>

<script>
let _pusherClient
function pusherClient() {
    if (!_pusherClient) {
        _pusherClient = new Pusher(
            '471292',
          {
              wsHost: 'soketi.fly.dev',
              wsPort: 443,
              wssPort: 443,
              forceTLS: true,
              encrypted: true,
              disableStats: true,
              enabledTransports: ['ws', 'wss'],
          }
        );
    }
    return _pusherClient;
}

document.addEventListener('DOMContentLoaded', function(){
  // subscribe to events
  const channel = this.pusherClient().subscribe('promotions')
  
  // listen to events
  channel.bind('summer-promo'), (d)=> {alert(d.message)})
})
<script>

Notes

  • <script defer..> - we are using the pusher javascript library directly from the CDN. You can also install it from NPM.
  • _pusherClient - open a new connection to the server.
  • const channel -.. - subscribe to the channel
  • `channel.bind` - listen for events with the name 'summer-promo' and create an alert.

Conclusion

In this article, we have seen how to deploy and run a production-grade WebSocket server and a few examples in python. If you are looking for a managed service that is still cheaper than Pusher Soketi now offers a cloud service based on Cloudflare workers.

Subscribe for regular updates

Last Updated 25 Sep 2022