NGINX Unit
v. 1.20.0

Starlette§

To run apps built with the Starlette web framework using Unit:

  1. Install Unit with a Python 3.5+ language module.

  2. Create a virtual environment to install Starlette’s PIP package:

    $ cd /path/to/app/
    $ python3 -m venv venv
    $ source venv/bin/activate
    $ pip install starlette[full]
    $ deactivate
    
  3. Let’s try a version of a tutorial app, saving it as /path/to/app/asgi.py:

    from starlette.applications import Starlette
    from starlette.responses import PlainTextResponse
    from starlette.routing import Route, Mount, WebSocketRoute
    
    
    def homepage(request):
        return PlainTextResponse('Hello, world!')
    
    def user_me(request):
        username = "John Doe"
        return PlainTextResponse('Hello, %s!' % username)
    
    def user(request):
        username = request.path_params['username']
        return PlainTextResponse('Hello, %s!' % username)
    
    async def websocket_endpoint(websocket):
        await websocket.accept()
        await websocket.send_text('Hello, websocket!')
        await websocket.close()
    
    def startup():
        print('Ready to go')
    
    
    routes = [
        Route('/', homepage),
        Route('/user/me', user_me),
        Route('/user/{username}', user),
        WebSocketRoute('/ws', websocket_endpoint)
    ]
    
    app = Starlette(debug=True, routes=routes, on_startup=[startup])
    

    Note

    This sample omits the static route because Unit’s quite capable of serving static files itself if needed.

  4. Set installation path permissions to secure access, for example:

    # chown -R app_user:app_group /path/to/app/
    

    Replace the placeholders above with actual values, noting them for later use in Unit configuration.

  5. Next, put together the Starlette configuration for Unit, adding a route to serve static content:

    {
        "listeners": {
            "*:80": {
                "pass": "routes"
            }
        },
    
        "routes": [
            {
                "match": {
                    "uri": "/static/*"
                },
    
                "action": {
                    "share": "/path/to/app/"
                }
            },
    
            {
                "action": {
                    "pass": "applications/starlette_app"
                }
            }
        ],
    
        "applications": {
            "starlette_app": {
                "type": "python 3",
                "user": "app_user",
                "group": "app_group",
                "path": "/path/to/app/",
                "home": "/path/to/app/venv/",
                "module": "asgi",
                "callable": "app"
            }
        }
    }
    
  6. Upload the updated configuration. Assuming the JSON above was added to config.json:

    # curl -X PUT --data-binary @config.json --unix-socket \
           /path/to/control.unit.sock http://localhost/config/
    

    Note

    The control socket path may vary; run unitd --help or see Startup for details.

  7. After a successful update, your app should be available on the listener’s IP address and port:

    $ curl http://localhost
    
          Hello, world!
    
    $ curl http://localhost/user/me
    
          Hello, John Doe!
    
    $ wscat -c ws://localhost/ws
    
          Connected (press CTRL+C to quit)
          < Hello, websocket!
          Disconnected (code: 1000, reason: "")