Deploying classification app with Starlette and Nginx as a reverse proxy

I have built a toy classifier to classify coca cola, pepsi cola, nuka cola vs other pictures as in Lesson 1, which I successfuly uploaded on Zeit using the provided example code: cola-image-classifer

I would like to deploy this app on my own ubuntu server running Nginx. It seems that I am almost there, but the app does not work properly, the image gets uploaded, but classification does not happen: cola-image-classifer-nginx.

Here is my Nginx configuration (based on online suggestions for Flask):

    # Cola image classifier
    location /imageclass/ {
          proxy_pass http://0.0.0.0:5042/;

          # Redefine the header fields that NGINX sends to the upstream server
         proxy_set_header Host $host;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

         # Define the maximum file size on file uploads
         client_max_body_size 5M;

        proxy_set_header X-Scheme $scheme;
 }

And here is the starlette-based app as in the provided code example:

from starlette.applications import Starlette
from starlette.responses import HTMLResponse, JSONResponse
from starlette.staticfiles import StaticFiles
from starlette.middleware.cors import CORSMiddleware
import uvicorn, aiohttp, asyncio
from io import BytesIO

from fastai import *
from fastai.vision import *

... more code ...

@app.route('/analyze', methods=['POST'])
async def analyze(request):
    data = await request.form()
    img_bytes = await (data['file'].read())
    img = open_image(BytesIO(img_bytes))
    return JSONResponse({'result': learn.predict(img)[0]})

if __name__ == '__main__':
    if 'serve' in sys.argv: uvicorn.run(app, host='0.0.0.0', port=5042)

I tried to search around the internet, but most of the related topics are for flask, and nothing for starlette or uvicorn.

It seems that I need to add a similar middleware to starlette like in this example for Flask: http://flask.pocoo.org/snippets/35/

I verified that the app works fine if I access it directly on the server, but I have an ssl_sertificate set up with Nginx, so it would be best to set it up via reverse proxy. Thanks.

1 Like

As a workaround, I have changed the client.js file to post to alternative destination when the host is my website:

if (`${loc.hostname}`== "blazys.com" || `${loc.hostname}`== "www.blazys.com" ) {
    xhr.open('POST', `${loc.protocol}//${loc.hostname}:${loc.port}/imageclass/analyze`, true);
} else {
    xhr.open('POST', `${loc.protocol}//${loc.hostname}:${loc.port}/analyze`, true);
}

And also changed the directory for static files in index.html

<head>
    <meta charset='utf-8'>
    <link rel='stylesheet' href='static/style.css'>
    <meta name="viewport" content="initial-scale=0.9">
    <script src='static/client.js'></script>
</head>

This line is added to index.html head, so that app looks OK on a smartphone:

    <meta name="viewport" content="initial-scale=0.9">  

And here is my Nginx configuration for the app:

    # Cola image classifier
    location /imageclass/ {
      proxy_pass http://0.0.0.0:5041/;

      # Defines a timeout for reading a response from the proxied server
      proxy_read_timeout 180s;

      # Redefine the header fields that NGINX sends to the upstream server
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

      # Define the maximum file size on file uploads
      client_max_body_size 5M;

      # proxy_set_header X-Scheme $scheme;
      proxy_set_header X-Script-Name /imageclass/;
    }

This seems to be working fine now: https://www.blazys.com/imageclass/ but if anyone have any suggestions for a cleaner implementation I would be grateful.

The updated scripts can be found in my github repository.