Source code

Revision control

Copy as Markdown

Other Tools

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.
.. admonition:: Heroku no longer offers a free tier.
:class: attention
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:
.. code-block:: console
$ 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``:
.. literalinclude:: ../../example/deployment/heroku/app.py
:language: python
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
:func:`~websockets.server.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:
.. literalinclude:: ../../example/deployment/heroku/requirements.txt
:language: text
Create a ``Procfile``.
.. literalinclude:: ../../example/deployment/heroku/Procfile
This tells Heroku how to run the app.
Confirm that you created the correct files and commit them to git:
.. code-block:: console
$ 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``:
.. code-block:: console
$ heroku create websockets-echo
Creating ⬢ websockets-echo... done
.. code-block:: console
$ 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.
 * [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:
.. code-block:: console
$ 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:
.. code-block:: console
$ python -m websockets 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:
.. code-block:: console
> 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:
.. code-block:: console
$ python -m websockets wss://websockets-echo.herokuapp.com/
>
In another shell, restart the app — again, replace ``websockets-echo`` with your
app:
.. code-block:: console
$ 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).
.. code-block:: console
$ python -m websockets 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).