Deploy to Fly - websockets 12.0 documentation
Description: This guide describes how to deploy a websockets server to Fly. We’re going to deploy a very simple app. The process would be identical for a more realistic app. Create application: Here’s the imple...

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

# Deploy to Fly

This guide describes how to deploy a websockets server to Fly.

The free tier of Fly is sufficient for trying this guide.

The free tier include up to three small VMs. This guide uses only one.

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

## 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 http
    import signal

    import websockets

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

    async def health_check(path, request_headers):
        if path == "/healthz":
            return http.HTTPStatus.OK, [], b"OK\n"

    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=8080,
            process_request=health_check,
        ):
            await stop

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

This app implements typical requirements for running on a Platform as a Service:

- it provides a health check at `/healthz`;

- it closes connections and exits cleanly when it receives a `SIGTERM` signal.

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

    websockets

The app is ready. Let’s deploy it!

## Deploy application

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

Sign up or log in to Fly.

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

    $ fly launch
    Creating app in ...
    Scanning source code
    Detected a Python app
    Using the following build configuration:
        Builder: paketobuildpacks/builder:base
    ? App Name (leave blank to use an auto-generated name): websockets-echo
    ? Select organization: ...
    ? Select region: ...
    Created app websockets-echo in organization ...
    Wrote config file fly.toml
    ? Would you like to set up a Postgresql database now? No
    We have generated a simple Procfile for you. Modify it to fit your needs and run "fly deploy" to deploy your application.

This will build the image with a generic buildpack.

Fly can build images with a Dockerfile or a buildpack. Here, `fly launch` configures a generic Paketo buildpack.

If you’d rather package the app with a Dockerfile, check out the guide to containerize an application.

Replace the auto-generated `fly.toml` with:

    app = "websockets-echo"
    kill_signal = "SIGTERM"

    [build]
      builder = "paketobuildpacks/builder:base"

    [[services]]
      internal_port = 8080
      protocol = "tcp"

      [[services.http_checks]]
        path = "/healthz"

      [[services.ports]]
        handlers = ["tls", "http"]
        port = 443

This configuration:

- listens on port 443, terminates TLS, and forwards to the app on port 8080;

- declares a health check at `/healthz`;

- requests a `SIGTERM` for terminating the app.

Replace the auto-generated `Procfile` with:

    web: python app.py

This tells Fly how to run the app.

Now you can deploy it:

    $ fly deploy

    ... lots of output...

    ==> Monitoring deployment

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

## 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 Fly app in this command:

    $ python -m websockets wss://websockets-echo.fly.dev/
    Connected to wss://websockets-echo.fly.dev/.
    >

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.fly.dev/
    Connected to wss://websockets-echo.fly.dev/.
    >

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

    $ fly restart websockets-echo
    websockets-echo is being restarted

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

    $ python -m websockets wss://websockets-echo.fly.dev/
    Connected to wss://websockets-echo.fly.dev/.
    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).