Deploy to Heroku - websockets 12.0 documentation
Description: This guide describes how to deploy a websockets server to Heroku. The same principles should apply to other Platform as a Service providers. We’re going to deploy a very simple app. The process wou...

Hide navigation sidebar
Hide table of contents sidebar
Back to top
Toggle table of contents sidebar

# Deploy to Heroku

This guide describes how to deploy a websockets server to Heroku. The same principles should apply to other Platform as a Service providers.

Heroku no longer offers a free tier.

When this tutorial was written, in September 2021, Heroku offered a free tier where a websockets app could run at no cost. In November 2022, Heroku removed the free tier, making it impossible to maintain this document. As a consequence, it isn’t updated anymore and may be removed in the future.

We’re going to deploy a very simple app. The process would be identical for a more realistic app.

## Create repository

Deploying to Heroku requires a git repository. Let’s initialize one:

    $ mkdir websockets-echo
    $ cd websockets-echo
    $ git init -b main
    Initialized empty Git repository in websockets-echo/.git/
    $ git commit --allow-empty -m "Initial commit."
    [main (root-commit) 1e7947d] Initial commit.

## Create application

Here’s the implementation of the app, an echo server. Save it in a file called `app.py`:

    #!/usr/bin/env python

    import asyncio
    import signal
    import os

    import websockets

    async def echo(websocket):
        async for message in websocket:
            await websocket.send(message)

    async def main():
        # Set the stop condition when receiving SIGTERM.
        loop = asyncio.get_running_loop()
        stop = loop.create_future()
        loop.add_signal_handler(signal.SIGTERM, stop.set_result, None)

        async with websockets.serve(
            echo,
            host="",
            port=int(os.environ["PORT"]),
        ):
            await stop

    if __name__ == "__main__":
        asyncio.run(main())

Heroku expects the server to listen on a specific port, which is provided in the `$PORT` environment variable. The app reads it and passes it to `serve()`.

Heroku sends a `SIGTERM` signal to all processes when shutting down a dyno. When the app receives this signal, it closes connections and exits cleanly.

Create a `requirements.txt` file containing this line to declare a dependency on websockets:

    websockets

Create a `Procfile`.

    web: python app.py

This tells Heroku how to run the app.

Confirm that you created the correct files and commit them to git:

    $ ls
    Procfile         app.py           requirements.txt
    $ git add .
    $ git commit -m "Initial implementation."
    [main 8418c62] Initial implementation.
     3 files changed, 32 insertions(+)
     create mode 100644 Procfile
     create mode 100644 app.py
     create mode 100644 requirements.txt

The app is ready. Let’s deploy it!

## Deploy application

Follow the instructions to install the Heroku CLI, if you haven’t done that yet.

Sign up or log in to Heroku.

Create a Heroku app — you’ll have to pick a different name because I’m already using `websockets-echo`:

    $ heroku create websockets-echo
    Creating ⬢ websockets-echo... done
    https://websockets-echo.herokuapp.com/ | https://git.heroku.com/websockets-echo.git

    $ git push heroku

    ... lots of output...

    remote: -----> Launching...
    remote:        Released v1
    remote:        https://websockets-echo.herokuapp.com/ deployed to Heroku
    remote:
    remote: Verifying deploy... done.
    To https://git.heroku.com/websockets-echo.git
     * [new branch]      main -> main

## Validate deployment

Let’s confirm that your application is running as expected.

Since it’s a WebSocket server, you need a WebSocket client, such as the interactive client that comes with websockets.

If you’re currently building a websockets server, perhaps you’re already in a virtualenv where websockets is installed. If not, you can install it in a new virtualenv as follows:

    $ python -m venv websockets-client
    $ . websockets-client/bin/activate
    $ pip install websockets

Connect the interactive client — you must replace `websockets-echo` with the name of your Heroku app in this command:

    $ python -m websockets wss://websockets-echo.herokuapp.com/
    Connected to wss://websockets-echo.herokuapp.com/.
    >

Great! Your app is running!

Once you’re connected, you can send any message and the server will echo it, or press Ctrl-D to terminate the connection:

    > Hello!
    < Hello!
    Connection closed: 1000 (OK).

You can also confirm that your application shuts down gracefully.

Connect an interactive client again — remember to replace `websockets-echo` with your app:

    $ python -m websockets wss://websockets-echo.herokuapp.com/
    Connected to wss://websockets-echo.herokuapp.com/.
    >

In another shell, restart the app — again, replace `websockets-echo` with your app:

    $ heroku dyno:restart -a websockets-echo
    Restarting dynos on ⬢ websockets-echo... done

Go back to the first shell. The connection is closed with code 1001 (going away).

    $ python -m websockets wss://websockets-echo.herokuapp.com/
    Connected to wss://websockets-echo.herokuapp.com/.
    Connection closed: 1001 (going away).

If graceful shutdown wasn’t working, the server wouldn’t perform a closing handshake and the connection would be closed with code 1006 (abnormal closure).