curl works on localhost but it doesn't work remotely - python

I wrote this small piece of code:
from flask import Flask
from flask_restful import Resource, Api
import subprocess
app = Flask(__name__)
api = Api(app)
class SlackReport(Resource):
def get(self):
subprocess.Popen(['python', 'ingestion_ice3_check.py'])
return 'Request submitted'
api.add_resource(SlackReport, '/slackReport')
if __name__ == '__main__':
app.run(debug=True)
If I execute:
curl --ipv4 http://127.0.0.1:5000/slackReport
the server sends the response but if I execute the same command from another machine in the same LAN I receive a 'connection refused' message
$ curl -X GET http://10.113.12.20:5000/slackReport
curl: (7) Failed to connect to 10.113.12.20 port 5000: Connection refused
If I request the resource from localhost I can see the request from the debug console of the server
127.0.0.1 - - [28/Sep/2017 18:15:02] "GET /slackReport HTTP/1.1" 200 -
However if I request the same resource from a remote machine I can see the packet on the port but the flask server doesn't receive anything.
$ sudo tcpdump -i ens192 port 5000
18:17:53.132514 IP 10.113.12.25.37096 > tl020dash.commplex-main: Flags [S], seq 3147843104, win 14600, options [mss 1460,sackOK,TS val 822032144 ecr 0,nop,wscale 7], length 0
This is the output of netstat command
sudo netstat -tnlp | grep :5000
tcp 0 0 127.0.0.1:5000 0.0.0.0:* LISTEN 21872/python

Your are running your service on localhost (127.0.0.1) so only your computer has access to it. If you want to run that Flask service so other stuff on your network can access it you can set some keyword args when you run your app. You might need to run this as an elevated user so it can bind to that network port (10.113.12.20:5000).
if __name__ == '__main__':
app.run(debug=True, host='10.113.12.20', port=5000)

Related

python websocket failure when run in openshift

I have a autobahn twisted websocket running in python which is working in a dev vm correctly but I have been unable to get working when the server is running in openshift.
Here is the shortened code which works for me in a vm.
from autobahn.twisted.websocket import WebSocketServerProtocol, WebSocketServerFactory, listenWS
from autobahn.twisted.resource import WebSocketResource
class MyServerProtocol(WebSocketServerProtocol):
def onConnect(self, request):
stuff...
def onOpen(self):
stuff...
def onMessage(self,payload):
stuff...
factory = WebSocketServerFactory(u"ws://0.0.0.0:8080")
factory.protocol = MyServerProtocol
resource = WebSocketResource(factory)
root = File(".")
root.putChild(b"ws", resource)
site = Site(root)
reactor.listenTCP(8080, site)
reactor.run()
The connection part of the client is as follows:
var wsuri;
var hostname = window.document.location.hostname;
wsuri = "ws://" + hostname + ":8080/ws";
if ("WebSocket" in window) {
sock = new WebSocket(wsuri);
} else if ("MozWebSocket" in window) {
sock = new MozWebSocket(wsuri);
} else {
log("Browser does not support WebSocket!");
window.location = "http://autobahn.ws/unsupportedbrowser";
}
The openshift configuration is as follows:
1 pod running with app.py listening on port 8080
tls not enabled
I have a non-tls route 8080 > 8080.
Firefox gives the following message in the console:
Firefox can’t establish a connection to the server at ws://openshiftprovidedurl.net:8080/ws.
when I use wscat to connect to the websocket.
wscat -c ws://openshiftprovidedurl.net/ws
I get the following error:
error: Error: unexpected server response (400)
and the application log in openshift shows the following:
2018-04-03 01:14:24+0000 [-] failing WebSocket opening handshake ('missing port in HTTP Host header 'openshiftprovidedurl.net' and server runs on non-standard port 8080 (wss = False)')
2018-04-03 01:14:24+0000 [-] dropping connection to peer tcp4:173.21.2.1:38940 with abort=False: missing port in HTTP Host header 'openshiftprovidedurl.net' and server runs on non-standard port 8080 (wss = False)
2018-04-03 01:14:24+0000 [-] WebSocket connection closed: connection was closed uncleanly (missing port in HTTP Host header 'openshiftprovidedurl.net' and server runs on non-standard port 8080 (wss = False))
Any assistance would be appreciated!
Graham Dumpleton hit the nail on the head, I modified the code from
factory = WebSocketServerFactory(u"ws://0.0.0.0:8080")
to
factory = WebSocketServerFactory(u"ws://0.0.0.0:8080", externalPort=80)
and it corrected the issue. I had to modify my index to point to the correct websocket but I am now able to connect.
Thanks!
Based on the source code of autobahn-python, you can get that message only in 2 cases.
Here is the implementation:
if not ((self.factory.isSecure and self.factory.externalPort == 443) or (not self.factory.isSecure and self.factory.externalPort == 80)):
return self.failHandshake("missing port in HTTP Host header '%s' and server runs on non-standard port %d (wss = %s)" % (str(self.http_request_host), self.factory.externalPort, self.factory.isSecure))
Because I think you are using Deployment + Service (and maybe Ingress on top of them) for your server, you can bind your server to port 80 instead of 8080 and set that port in Service and in Ingress, if you are using them.

Cannot access Flask with apache

I have a linux server which I am running my flask app on it like this:
flask run --host=0.0.0.0
Inside the server I can access it like this:
curl http://0.0.0.0:5000/photo (and I am getting a valid response)
However, when I am trying to access it outside the server:
http://my_ip:5000/photo - the connection is refused.
The same ip, will return an image saved on public_html with apache2 configured
http://my_ip/public_html/apple-touch-icon-144x144-precomposed.png
I use this simple snippet to get the ip-address from the interface
import socket
def get_ip_address():
""" get ip-address of interface being used """
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
return s.getsockname()[0]
IP = get_ip_address()
And in main:
if __name__ == '__main__':
app.run(host=IP, port=PORT, debug=False)
And running:
./app.py
* Running on http://10.2.0.41:1443/ (Press CTRL+C to quit)
I have a suspicion you have a firewall on your Linux machine that is blocking port 5000.
Solution 1:
Open the relevant port on your firewall.
Solution 2:
I would suggest you to install nginx as a web proxy and configure it so that http://my_ip/photo would forward traffic to and from http://127.0.0.1:5000/photo:
server {
listen 80;
location /photo {
proxy_pass http://127.0.0.1:5000/photo;
}
}

Heroku Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch

I keep getting this error despite trying everything out in internet.
I'm trying to run my flask application on Heroku.
Below is my ProcFile
web gunicorn -b 127.0.0.1:8000 geeni:app
Below is my geeni.py file.
class ChargeUser(Resource):
def post(self):
jsonData = request.get_json(force=True)
stripeid = jsonData['stripeid_customer']
currency = jsonData['currency']
amount = jsonData['amount']
apiKey = jsonData['api_key']
try:
stripe.Charge.create(amount = amount, source=stripeid, currency=currency)
return jsonify({'Msg':'Charged!'})
except:
raise
api.add_resource(ChargeUser,'/')
if __name__ == '__main__':
app.run()
I've setup my heroku push/login everything and have throughly followed tutorials. No luck..
Your Procfile should be web: gunicorn -b 0.0.0.0:$PORT greeni:app. As currently written, Heroku would never see that your application is ready to receive inbound connections:
The 127.0.0.1 interface would not receive any external network traffic. Instead, the 0.0.0.0 string does bind to the all external interfaces.
Heroku passes the required port via the $PORT variable, which is usually 5000.
Remember - Heroku manages the "routing mesh", which receives the inbound HTTP traffic, then forwards it to your application. It assigns the address and port, which can't be hard-coded in your Procfile.

python flask server port deforced by ntpd

I have a rest server implemented by python with flask. And implement an api to restart ntpd. The code test_flask.py:
from flask import Flask
import subprocess
import logging
import sys
app = Flask(__name__)
def run_shell_cmd(cmd):
logging.info("run cmd: %s", cmd)
try:
rc = subprocess.call(cmd, shell=True)
if rc != 0:
logging.error("Fail to run %s , rc: %s" % (cmd, rc))
except OSError as e:
logging.error("Fail to run cmd: %s" % e)
return rc
#app.route("/restart_ntpd")
def restart():
run_shell_cmd("service ntpd restart")
return "Success!"
if __name__ == "__main__":
LOG_FORMAT = '%(asctime)s, %(levelname)s, %(filename)s:%(lineno)d, %(message)s'
logging.basicConfig(
format=LOG_FORMAT,
level=logging.INFO,
stream=sys.stdout,
)
app.run()
Then I operated as follow:
start flask server: python test_flask.py
curl "http://localhost:5000/restart_ntpd. Then ntpd restart & return "success"
stop flask server: just use Ctrl+c to stop
start flask server again, it will raise a exception:
socket.error: [Errno 98] Address already in use.
use sh $ netstat -ntlp | grep 5000, the port was deforced by ntpd
I think the ntpd will use port 123 in default. In my scene, why the port 5000 is deforced by ntpd? Is it the problem of flask?
ntpd is not listening on TCP port 5000 itself, it's the environment where it is running - the process.
And that process is a child of your Flask server process, which opens a socket listening on TCP port 5000.
This socket is inherited in the child process, and since the ntpd process is a long-running one, it continues running with the socket it inherits from you, occupying the port 5000.
Check how to deal with Python BaseHTTPServer killed,but the port is still be occupied? on how to prevent children processes from inheriting the socket.
Of course, first you have to find a way to customize the way Flask start the server.

Is it possible to run python SimpleHTTPServer on localhost only?

I have a vpn connection and when I'm running python -m SimpleHTTPServer, it serves on 0.0.0.0:8000, which means it can be accessed via localhost and via my real ip.
I don't want robots to scan me and interested that the server will be accessed only via localhost.
Is it possible?
python -m SimpleHTTPServer 127.0.0.1:8000 # doesn't work.
Any other simple http server which can be executed instantly using the command line is also welcome.
In Python versions 3.4 and higher, the http.server module accepts a bind parameter.
According to the docs:
python -m http.server 8000
By default, server binds itself to all interfaces. The option
-b/--bind specifies a specific address to which it should bind. For example, the following command causes the server to bind to localhost
only:
python -m http.server 8000 --bind 127.0.0.1
New in version 3.4: --bind argument was introduced.
As #sberry explained, simply doing it by using the nice python -m ... method won't be possible, because the IP address is hardcoded in the implementation of the BaseHttpServer.test function.
A way of doing it from the command line without writing code to a file first would be
python -c 'import BaseHTTPServer as bhs, SimpleHTTPServer as shs; bhs.HTTPServer(("127.0.0.1", 8888), shs.SimpleHTTPRequestHandler).serve_forever()'
If that still counts as a one liner depends on your terminal width ;-) It's certainly not very easy to remember.
If you read the source you will see that only the port can be overridden on the command line. If you want to change the host it is served on, you will need to implement the test() method of the SimpleHTTPServer and BaseHTTPServer yourself. But that should be really easy.
Here is how you can do it, pretty easily:
import sys
from SimpleHTTPServer import SimpleHTTPRequestHandler
import BaseHTTPServer
def test(HandlerClass=SimpleHTTPRequestHandler,
ServerClass=BaseHTTPServer.HTTPServer):
protocol = "HTTP/1.0"
host = ''
port = 8000
if len(sys.argv) > 1:
arg = sys.argv[1]
if ':' in arg:
host, port = arg.split(':')
port = int(port)
else:
try:
port = int(sys.argv[1])
except:
host = sys.argv[1]
server_address = (host, port)
HandlerClass.protocol_version = protocol
httpd = ServerClass(server_address, HandlerClass)
sa = httpd.socket.getsockname()
print "Serving HTTP on", sa[0], "port", sa[1], "..."
httpd.serve_forever()
if __name__ == "__main__":
test()
And to use it:
> python server.py 127.0.0.1
Serving HTTP on 127.0.0.1 port 8000 ...
> python server.py 127.0.0.1:9000
Serving HTTP on 127.0.0.1 port 9000 ...
> python server.py 8080
Serving HTTP on 0.0.0.0 port 8080 ...

Categories