I had been using the Python socket module to create a very basic client-server for testing purposes, but soon I wanted to have something slightly more standard, like an HTTP server. I decided to try the Python Flask framework.
First I set up a Flask server on a CentOS 7 Linux VM running on VirtualBox:
# yum install python-pip
# pip install Flask
# mkdir flask-server && cd flask-server
I created the hello.py
file as described on the Flask homepage:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
Likewise, I started running Flask:
# FLASK_APP=hello.py flask run
* Serving Flask app "hello"
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Then I set up port forwarding in VirtualBox on my desktop host so that I could communicate with the virtual machine, using the following settings:
Name: flask
Protocol: TCP
Host IP: 127.0.0.1
Host Port: 9500
Guest IP: 10.0.2.16
Guest Port: 5000
I tested it in a browser (Firefox) on my desktop at http://127.0.0.1:9500/
No connection. Firefox endlessly tries to load the file.
I tried from the local machine itself:
# curl http://localhost:5000/
Hello World!
I tried running tcpdump
to see what the network traffic to that port looked like:
# tcpdump -n -i enp0s3 port 5000
...
14:54:11.938625 IP 10.0.2.2.63923 > 10.0.2.16.commplex-main: Flags [S], seq 3067208705, win 65535, options [mss 1460], length 0
...
Over and over I saw the same SYN packet from the client host, but the server never replied with a SYN-ACK.
I also noted that the local port was labeled commplex-main
. This label is from /etc/services
:
# grep commplex /etc/services
commplex-main 5000/tcp #
commplex-main 5000/udp #
commplex-link 5001/tcp #
commplex-link 5001/udp #
I don’t know what commplex-main
is, but since I’m not running anything else on port 5000 other than Flask, it shouldn’t matter.
It turned out there were 2 separate problems:
- Flask was listening only on localhost
- firewalld was blocking the requests from external hosts
To fix the first, run Flask with the host flag:
# FLASK_APP=hello.py flask run --host=0.0.0.0
* Serving Flask app "hello"
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
(This is mentioned in the Flask Quickstart guide, under Externally Visible Server.)
You can also specify an alternative port, e.g.:
# FLASK_APP=hello.py flask run --host=0.0.0.0 --port=56789
* Serving Flask app "hello"
* Running on http://0.0.0.0:56789/ (Press CTRL+C to quit)
To fix the latter temporarily, I disabled firewalld
:
systemctl stop firewalld
systemctl disable firewalld
Obviously, if you are dealing with a machine connected directly to the Internet, this would be a terrible solution. You’d want to add rules allowing only the hosts and ports from which you expect to receive connections. But for testing communications between my desktop and a virtual host running on it, this seemed like a quick solution.
After those 2 changes, I was able to load the sample “hello” Flask app in a browser:
That “–host=0.0.0.0” argument to flask helped as I’m running off vbox as well. Thanks!
I ran into this problem again with an AWS EC2 instance running CentOS 7.5. By default, the iptables rules allowed only SSH connections:
I added a rule to accept TCP connections on port 5000:
I then saved the rules:
Of course I forgot that iptables isn’t running as a service on this host (it’s running firewalld), but adding the iptables rule fixed the problem (at least for now).
This worked great, thank you so much!