Running cherrypy app on AWS: socket could not be created - python

I have developed a small web app on my Windows PC and tested it locally.
Then I wanted to transfer it to an AWS Ubuntu 18 instance.
For the sake of brevity, the app processes a form from a webpage and redirects a user to the page with the result. The contents of the app do not really matter, since the error occurs before you can interact with it.
I have not encountered any issues running it locally (i.e. the same code as below, w/out cherrypy.config.update).
import cherrypy
import os
filepath = os.getcwd()
class MyApp(object):
#cherrypy.expose
def index(self):
with open('./index.html', 'r') as f:
text = f.read()
return text
#cherrypy.expose
def process_filled_form(self, field1, field2):
out = filed1+field2
return(out)
if __name__ == '__main__':
config = {"/folder": {"tools.staticdir.on": True,
"tools.staticdir.dir": os.path.join(filepath, "folder")}}
cherrypy.config.update({'server.socket_host': 'XXX.XXX.XXX.XXX',
'server.socket_port': 9028,})
cherrypy.quickstart(MyApp(), '/', config)
But when I try to make the app public on an AWS instance, I get the following error:
[06/Mar/2021:06:25:12] ENGINE Listening for SIGTERM.
[06/Mar/2021:06:25:12] ENGINE Listening for SIGHUP.
[06/Mar/2021:06:25:12] ENGINE Listening for SIGUSR1.
[06/Mar/2021:06:25:12] ENGINE Bus STARTING
[06/Mar/2021:06:25:12] ENGINE Started monitor thread 'Autoreloader'.
[06/Mar/2021:06:25:12] ENGINE Error in HTTP server: shutting down
Traceback (most recent call last):
File "/home/user/.conda/envs/user_app/lib/python3.9/site-packages/cherrypy/process/servers.py", line 225, in _start_http_thread
self.httpserver.start()
File "/home/user/.conda/envs/user_app/lib/python3.9/site-packages/cheroot/server.py", line 1836, in start
self.prepare()
File "/home/user/.conda/envs/user_app/lib/python3.9/site-packages/cheroot/server.py", line 1791, in prepare
raise socket.error(msg)
OSError: No socket could be created -- (('XXX.XXX.XXX.XXX', 9028): [Errno 99] Cannot assign requested address)
[06/Mar/2021:06:25:12] ENGINE Bus STOPPING
[06/Mar/2021:06:25:12] ENGINE HTTP Server cherrypy._cpwsgi_server.CPWSGIServer(('XXX.XXX.XXX.XXX', 9028)) already shut down
[06/Mar/2021:06:25:12] ENGINE Stopped thread 'Autoreloader'.
[06/Mar/2021:06:25:12] ENGINE Bus STOPPED
[06/Mar/2021:06:25:12] ENGINE Bus EXITING
[06/Mar/2021:06:25:12] ENGINE Bus EXITED
Changing the socket does not affect anything. The app produces no errors when launched locally on AWS.
I am totally new to anything web-related, so the problem might be smt very obvious. Perhaps, I am missing something in the config, or `quickstart` may not be the right option to launch the app.
Please help

Most likely you are binding to a wrong address.
In you config.update call, modify the socket_host value to 0.0.0.0:
cherrypy.config.update({'server.socket_host': '0.0.0.0',
'server.socket_port': 9028,})
That should allow your app to listen for requests on all the network addresses that are available in your host.

Related

Flask Socket on Ubuntu AWS is not receive message/data, but in the local machine it works fine, no Connect refused

Situation:
I deploy my flask server in the AWS EC2 ubuntu and running. And react.js running on my local machine try to test is remote server setup correctly and works, contains Restful API and WebSocket.
Question:
Everything works fine on the local machine which python and react both running on the local machine. When l make flask running on the AWS, the Restful API works fine, but WebSocket is not working, there is no connect refused error, switch protocol is 101 and in the inspector network section is 200 status. Just remote server cannot receiving data. I am not sure what was happended at this time and how to fix that, anyone has the same experience?
this one is my client
const endPoint = "http://3.237.172.105:5000/friends";
const socket = io.connect(endPoint);
const addFriends=(friend)=>{
socket.emit("Addedfriend",{username:name , friendName:friendName});
}
this one is my flask start file: call python3 app.py to run
from logging import debug
from flask import Flask
from flask_socketio import SocketIO
from flask_cors import CORS
from Controller.logReg import logReg
from Controller.profile import profile
from Controller.ticket import ticket
from Controller.personal import personal
import logging
#log = logging.getLogger('werkzeug')
#log.setLevel(logging.ERROR)
app = Flask(__name__)
socketio = SocketIO(app, cors_allowed_origins="*")
app.register_blueprint(logReg)
app.register_blueprint(profile)
app.register_blueprint(ticket)
app.register_blueprint(personal)
print("socket started ... ...")
CORS(app)
if __name__ == '__main__':
print("socket opened")
socketio.run(app, host='0.0.0.0', port=5000)
this is my socket file: print data is not print anything and I am not sure why
#socketio.on('Addedfriend', namespace='/friends')
def add_friend(data, t):
print("this is from addFriend" + str(data))
# print("friend SID: "+str(request.sid))
user = data['username']
friend = data['friendName']
user_friends = FriendsDB.find_one({"username": user})['friends']
if friend in user_friends:
emit("Addedfriend", {"result": "already added", "friendPhoto":"", "friendStatus": False})
return
if FriendsDB.find_one({"username": friend}) is None:
emit("Addedfriend", {"result": "Not Exist", "friendPhoto": "", "friendStatus": False})
return
this is the network screenshot
this is AWS IP address
this is AWS inbound rule

grpc client dns resolution failed when trying to access grpc server on same network

I'm trying to call a GRPC server running on a .Net Core project from a Python client.
When running against localhost:5001 it works fine, but running against the actual IP of the machine from within the same network like 192.168.1.230:5001 it doesn't work and I get an error DNS resolution failed.
I've downloaded the SSL cert and am at the moment reading it as a file from the client. It works when running against localhost so I don't think that is the problem.
Is there a better way to do this kind of testing of having clients run on separate devices but on the same network as the server? Hosting the GRPC server outside during development doesn't really seem like the best solution.
Python code:
import grpc
import datamessage_pb2 as datamessage
import datamessage_pb2_grpc as datamessageService
def main():
print("Calling grpc server")
with open("localhost.cer", "rb") as file:
cert = file.read()
credentials = grpc.ssl_channel_credentials(cert)
channel = grpc.secure_channel("https://192.168.1.230:5001", credentials)
# channel = grpc.secure_channel("localhost:5001", credentials)
stub = datamessageService.StationDataHandlerStub(channel)
request = datamessage.StationDataModel(
temperature=22.3, humidity=13.3, soilMoisture=35.0)
result = stub.RegisterNewStationData(request)
print(result)
main()
Server settings in Program.cs:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseUrls("https://*:5001");
webBuilder.UseStartup<Startup>();
});
Settings in firewall:
Traceback:
grpc._channel._Rendezvous: <_Rendezvous of RPC that terminated with:
status = StatusCode.UNAVAILABLE
details = "DNS resolution failed"
debug_error_string = "{"created":"#1576101634.549000000","description":"Failed to pick subchannel","file":"src/core/ext/filters/client_channel/client_channel.cc","file_line":3934,"referenced_errors":[{"created":"#1576101634.549000000","description":"Resolver transient failure","file":"src/core/ext/filters/client_channel/resolving_lb_policy.cc","file_line":262,"referenced_errors":[{"created":"#1576101634.549000000","description":"DNS resolution failed","file":"src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc","file_line":202,"grpc_status":14,"referenced_errors":[{"created":"#1576101634.549000000","description":"OS Error","file":"src/core/lib/iomgr/resolve_address_windows.cc","file_line":96,"os_error":"No such host is known.\r\n","syscall":"getaddrinfo","wsa_error":11001}]}]}]}"
In Python gRPC client, calling channel without protocol (https:) is required. So, I called gRPC service in dotnet core framework with following and it worked. Note, dotnet gRPC server was listening on https://localhost:5001.
with open('localhost.crt', 'rb') as f:
credentials = grpc.ssl_channel_credentials(f.read())
with grpc.secure_channel('localhost:5001', credentials) as channel:
stub = pb2_grpc.GreeterStub(channel)
request = pb2.HelloRequest(name = "GreeterPythonClient")
response = stub.SayHello(request)

Moving from localhost to real URL in Flask?

I'm developing a site with Python and Flask and want to move from localhost in my browser to my team's development server and development site but I'm having problems. I've already looked at the Flask documentation, which recommends using host='0.0.0.0' or specifying SERVER_NAME. Thusfar, neither of these things have helped. Here's a bit of code to show what I'm doing:
app = Flask(__name__)
if __name__ == '__main__':
app.secret_key = 'super secret key'
app.config['SERVER_NAME'] = 'https://example.org/blah'
app.run(host=app.config['SERVER_NAME'], port=4343, debug=True)
As you can see, instead of localhost:500, I want to be able to go into my browser and visit 'https://example.org/blah' and see the same things.
With this piece of code, I get this error:
(py34)user:~/flask$ python app.py
INFO - Connection with server established!
INFO - Server version meets recommendations (v2.9)
Traceback (most recent call last):
File "app.py", line 18, in <module>
app.run(host=app.config['SERVER_NAME'], port=4343, debug=True)
File "/home/me/anaconda3/envs/py34/lib/python3.4/site-packages/flask/app.py", line 772, in run
run_simple(host, port, self, **options)
File "/home/me/anaconda3/envs/py34/lib/python3.4/site-packages/werkzeug/serving.py", line 674, in run_simple
s.bind((hostname, port))
socket.gaierror: [Errno -2] Name or service not known
If instead of using SERVER_NAME I use host='0.0.0.0', I don't get any errors and it will successfully start "Running on http://0.0.0.0:4343/" but I can't follow that url into my browser the same way I can when I connect to my localhost.
What do I need to do to get my flask app running on https://example.org/blah?
Also, if it helps to know, I have to ssh into my server.
If you run with host='0.0.0.0' from the server, you should be able to navigate to example.org:4343 and see your app.
Additionally, SERVER_NAME requires the port, per the documentation:
the name and port number of the server. Required for subdomain support (e.g.: 'myapp.dev:5000')
Finally, if you want to show you app without a port number, you either need to run it at port 80 (or 443) with root permissions, or using Nginx/Apache to route the request from your domain to the app.

Connection error with Tornado Websockets + Django + Azure + Apache

I am running my application with Windows Azure on a Virtual Machine with ubuntu 14.04 lts. I am running my Django application through WSGI on Apache.
Previously i ran django locally with the command "python manage.py runserver", and every thing worked fine when my website connected to my sockets.py file from website.html.
I am running Django through Apache on public ip port 80
I am running the sockets.py separately in a terminal through Putty
I am reading the error through the Google Chrome console
Suddenly this error occurs: Failed to execute 'send' on 'WebSocket': Still in CONNECTING state. whenever i try to connect to the socket.
After a while my page response with: failed: Error in connection establishment: net::ERR_CONNECTION_TIMED_OUT
website.html js:
ws = new WebSocket("ws://10.77.22.74:1339/ws");
function load_all() {
target = "load_all"
ws.send(target)
}
ws.onmessage = function(evt) {
console.log(evt.data)
}
The ip is my internal ip on my virtual machine.
sockets.py:
import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web
class WSHandler(tornado.websocket.WebSocketHandler):
def check_origin(self, origin):
return True
def open(self):
print 'new connection'
def on_message(self, message):
self.write_message(message)
def on_close(self):
print 'connection closed'
application = tornado.web.Application([
(r'/ws', WSHandler),
])
if __name__ == "__main__":
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(1339)
tornado.ioloop.IOLoop.instance().start()
I have tried to change the http_server.listen(1339) to http_server.listen(1339, adress='10.77.22.74') (sockets.py)
I have tried using my public ip and opening a port through tcp (endpoints) and adjusting the scripts after that (sockets.py & website.html)
I have tried running with the localhost & 127.0.0.1 (sockets.py & website.html)
I have tried with ws & wss
I still get the error for some reason, do i need to give Apache (www-data) some permissions to connect to the sockets.py?
Which IP should i use, both on socket.py and website.htm?
Solved
Turn out Tornado is listening to all IP:s if you not specify the adress in the socket server. I opened a port on the public IP and used that IP for my javascript socket connection.

Configuring cherrypy for global usage

I'm trying to test cherrypy framework by using example from their site:
import cherrypy
class HelloWorld(object):
def index(self):
return "Hello World!"
index.exposed = True
cherrypy.quickstart(HelloWorld())
When I run it I get this response in the console:
[05/Dec/2011:00:15:11] ENGINE Listening for SIGHUP.
[05/Dec/2011:00:15:11] ENGINE Listening for SIGTERM.
[05/Dec/2011:00:15:11] ENGINE Listening for SIGUSR1.
[05/Dec/2011:00:15:11] ENGINE Bus STARTING
CherryPy Checker:
The Application mounted at '' has an empty config.
[05/Dec/2011:00:15:11] ENGINE Started monitor thread '_TimeoutMonitor'.
[05/Dec/2011:00:15:11] ENGINE Started monitor thread 'Autoreloader'.
[05/Dec/2011:00:15:12] ENGINE Serving on 127.0.0.1:8080
[05/Dec/2011:00:15:12] ENGINE Bus STARTED
When running browser locally and pointing to localhost:8080 it works. How can I configure the application so that it responds to a domain name say: www.example.com? I want the Hello World to be tested in my production server having the domain name, so that it can be accessed by anyone over the world from any location or any computer?
You'll use the static ip for the production server...
config = {
'global' : {
'server.socket_host' : 'XXX.XXX.XXX.XXX',
'server.socket_port' : 80,
}
}
cherrypy.quickstart(HelloWorld(), '/', config)
Then have a dns entry for your domain, www.example.com, pointed to the static ip.
Hope this helps!

Categories