Search code examples
pythonazureremote-debuggingremote-serverbottle

Bottle server on remote machine


I'm trying to test communication between simple bottle front and backends. I'm able to get things to work on localhost on my machine, but I encounter unexpected behavior when I run the same code on a remote azure machine.

I put three files in one folder, frontend_server.py, backend_server.py, and index.html. Locally, if I run the first two servers in a terminal, then navigating to localhost:4040 shows the expected output in the developer console (it prints an object {"test_backend": "test"}). What I would like to do is run the same servers on a remote machine (12.123.123.123, say) and see the same output printed to the developer console when I navigate to http://12.123.123.123:4040. However, in this case, I see POST http://0.0.0.0:8080/test net::ERR_CONNECTION_REFUSED. I have also tried changing the POST URL to the remote machine's address -- in this case, the connection times out after about 10 seconds.

I suspect there is an issue with the configuration of the remote server. However, I have set inbound rules to * for both ports 4040 and 8080.

Here is my backend. I thought there might be a CORS issue, so included the after_request hook. It doesn't seem to ever execute, however (no message is printed to the python console).

#! /usr/bin/env python3
import beaker.middleware
import bottle
import json
app = bottle.Bottle()


@app.hook("after_request")
def enable_cors():
    '''From https://gist.github.com/richard-flosi/3789163

    This globally enables Cross-Origin Resource Sharing (CORS) headers for every response from this server.
    '''
    print("after request")
    bottle.response.headers['Access-Control-Allow-Origin'] = '*'
    bottle.response.headers['Access-Control-Allow-Methods'] = 'PUT, GET, POST, DELETE, OPTIONS'
    bottle.response.headers['Access-Control-Allow-Headers'] = 'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token'


@app.post("/test")
def test():
    print("this is just a test")
    bottle.response.content_type = "application/json"
    return json.dumps({"test_backend": "test"})

bottle.run(app, host="0.0.0.0", port="8080")

This is my frontend,

#! /usr/bin/env python
import sys
import os
import bottle
import argparse


@bottle.get("/")
def root_app():
    return bottle.static_file("index.html", root="./")


def main():
    parser = argparse.ArgumentParser(description="Frontend Server")
    parser.add_argument("--host", action="store", dest="host", type=str, help="Host to bind to", default="0.0.0.0")
    parser.add_argument("--port", action="store", dest="port", type=int, help="Port to listen on", default="4040")
    args = parser.parse_args(sys.argv[1:])

    bottle_server_kwargs = {
        "host": args.host,
        "port": args.port,
        "server": "tornado",
        "reloader": False
    }
    bottle.run(**bottle_server_kwargs)
    return


if __name__ == '__main__':
    main()

This is how I make the POST request, in an index.html,

<!doctype html>
<html>
  <head>
    <script src = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.js"></script>
  </head>
  <body>
  </body>
  <script type="text/javascript">
   $.ajax({
       type: 'POST',
       crossDomain:'true',
       url: "http://0.0.0.0:8080/test",
       success: function(response){
           console.log("success");
           console.log(response);
       }
   });
  </script>
</html>

Any ideas about what might be happening?


Solution

  • The issue was solved by @Joran Beasley's comment, add it as the answer to close the question :

    in your ajax call url: http://0.0.0.0:8080/test should be url: http://64.243.2.11:8080/test (or whatever the actual IP of the host is ...) 0.0.0.0 just means "listen on all interfaces", its not actually the IP address you are talking to.