I am trying to teach myself Flask in a Vagrant environment. I understand that Flask runs a server on port 5000 by default. In my Vagrantfile I have:
config.vm.network :forwarded_port, guest: 80, host: 8080
config.vm.network :forwarded_port, guest: 5000, host: 5000
I have a simple tutorial Flask app:
from flask import Flask
app = Flask(__name__)
#app.route('/hello')
def hello_world():
return 'Hello world!'
if __name__ == '__main__':
app.run(debug=True)
Yet when I run python hello.py in my Vagrant environment and subsequently go to 127.0.0.1:5000/hello in Chrome on my desktop, I can't connect.
I don't know nearly enough about networking. What am I missing?
If you are accessing from Chrome in your desktop, you are technically accessing from a different computer (hence you need to place host='0.0.0.0' as argument to app.run() to tell the guest OS to accept connections from all public (external) IPs.
This is what worked for me (for both 127.0.0.1:5000/hello and localhost:5000/hello in Chrome):
from flask import Flask
app = Flask(__name__)
#app.route("/hello")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run(host='0.0.0.0')
You possibly need to get Flask to serve on an externally-visible URL: see the docs
This may be caused by Vagrant (VirtualBox) NAT Port forwarding not working properly (port conflicts).
To narrow down the issue, you may want to make sure that port 5000 is open correctly on both end, this can be done by using nmap, nc (netcat) or netstat etc.
e.g. on host
nmap 127.0.0.1
nc -vz 127.0.0.1 5000
curl http://127.0.0.1:5000
Within the guest
nmap GUEST_IP
nc -vz GUEST_IP 5000
curl http://GUEST_IP:5000
NOTE: GUEST_IP is most likely in the 10.0.2.0/24 network (vbox NAT engine default).
Running these commands on both your host and within the VM (guest box) will tell you if the ports are open.
Make sure your python hello world binds NOT ONLY to the loopback device so that it can serve requests from external clients.
Use lsof -i :5000 or netstat -nap | grep :5000 to determine which program is binding the port for further troubleshooting.
Do you have curl installed in your vagrant box? If not install it and try curl http://127.0.0.1:5000/hello. If you get a response and you see Hello world! in your console, then on flask side everything is fine. Back to the virtual box - When you open the network settings, from what you said above, I assume you are using a NAT address. In that case you will need to set the host address to 127.0.0.1, port 5000, leave the guest address empty and put port 5000 again and that should do the trick(port forwarding). One thing I've noticed about vagrant in those situations is that it works best if you use virtualhosts. Take a look here.
I was using Vagrant and solved it by adding this line of code to Vagrantfile:
config.vm.network "forwarded_port", guest: 5000, host: 5000, host_ip: "127.0.0.1"
make sure to 'vagrant reload' after you change your Vagrantfile
Related
I heard that all the 127.x.x.x are loopback IPs. So I try to run Flask on 127.0.0.2 but It gets error "Can't assign requested address" instead. While it works fine on 127.0.0.1
So how can I run flask on 127.0.0.x ?
Looks like your OS is a MacOS. MacOS using only 127.0.0.1 for loopback interface
But it is possible to assign 127.0.0.XX aliases manually
This article has couple solutions how to do that
Maybe what you looking for is to expose flask api on a different host than localhost(127.0.0.1)
You can choose a different port
app.run(host="0.0.0.0", port=8888)
Or host with machine hostname
from socket import gethostname
gethostname()
For custom hostname, add it in /etc/hosts file, it probably already contains a line about 127.0.0.1, in which case you just add your alias to the list
127.0.0.1 localhost localhost.localdomain myappname
in app
app.config['SERVER_NAME'] = 'myappname:5000'
for public, you would need to configure a specific dns
I am able to run a webserver using the following code
from flask import Flask
from waitress import serve
app = Flask(__name__, static_url_path='/static')
...
serve(app, port=8080)
The problem is that I can access it only from the machine where it is running, if I try to access it using the ipv4 ip, it doesn't work. Am I missing a step?
Simple example,try it!
I hope it will help you.
app1.py
from flask import Flask
app = Flask(__name__)
# app.run(host='0.0.0.0', port=8080,debug=True)
waitress_server.py
from waitress import serve
import app1
serve(app1.app, host='0.0.0.0', port=8080)
Then run below command
python waitress_server.py
Waitress now provides a simple command line Utility called waitress-serve for running the Flask Application. Please note that this answer is valid for Waitress 1.30. The command line arguments could change in future.
If your Flask application is called myapplication and the method which instantiates your application is called create_app, then you can run the command below. This will launch the server listening on port 8080 by default.
waitress-serve --call "myapplication:create_app"
If you wish to launch it on port 80 (http), then all you need to do is:
waitress-serve --port=80 --call "myapplication:create_app"
D:\flaskapps>waitress-serve --port 80 --call "dlrlsummarizer:create_app"
Serving on http://ADITHYA-PC:80
Waitress serve command line arguments.
Flask 1.0 production deployment tutorial.
Try using
serve(app, host='0.0.0.0', port=8080)
I ran into this question and looking something similar.
After looking at the documentation and combined with your original request, I tested
serve(app, port=8080, host="x.x.x.x")
Where x.x.x.x is my host ip address.
It works fine on my end.
Complete code
from flask import Flask
from waitress import serve
app = Flask(__name__)
...
serve(app, port=8080, host="x.x.x.x")
I realize this question was probably based in a miss-diagnosed firewall or NAT issue, but in case people come here actually wanting to serve a Flask app with waitress on windows properly (as a service), I want to point to my answer here, so that it can be of use and receive some feedback.
from flask import Flask
from waitress import serve
app = Flask(__name__)
#app.route("/")
def hello_world():
return "<p>Hello stay healthy.</p>"
if __name__ == "__main__":
serve(app, host="127.0.0.1", port=8080)
Problem may persist in host. You can use host="127.0.0.1" in your program.
Save your program in app.py file.
Run your program.
The server will be accessible at http://localhost:8080
I just realized that can be reached by computers in the same network, but not from computers outside of the network
You need to forward the port in your router and use your public IP address.
To be able to use your internal PC (behind the router) you need to forward in the router the externl port 8080 to internal port 8080 and IP address of your server.
In this conditions you can access your server from outside your network using your external IP. That is OK if you have a static IP address allocated by your provider. If not than you can use a free DNS provider (I use DnsExit) which will provide you with a name for your external IP address. This way you can access your server with a name even if the IP address from your service provider changes from time to time.
I work on a linux cluster that is behind a firewall. It does not have web access.
I had this idea I could try to run flask and direct it to a port I know is open (5901 for vnc), and then tunnel that port and view it in my browser.
It's not working so far. Is this possible at all?
Here is what I'm doing:
helloflask.py
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run(host='0.0.0.0', port=5901)
#app.run()
I run python helloflask.py then
ssh -L 5901:<inner server>:5901 <outer server>
Then I navigate to localhost:5901. Nothing. I also tried links localhost:5901 and links <server>:5901, but again nothing.
Is it possible there is some way to do this?
You can do this :
Run your flask app or notebook on the remote server on any port. Say for example port 5000.
On your local machine run below command to establish the ssh tunnelling :
ssh -D 8123 -f -C -q -N username#remotesrrver
The port 8123 is arbitrary here it can be any allowed port on your local machine. Then setup one of your browser (Fire fox may be) to use socks proxy on port 8123
Make sure that the traffic is proxied for localhost also. By default Firefox disable proxying for localhost. Once these are established you should be able to go to http://localhost:5000 on your browser to hit the app /notebook running on the remote machine
And your hellowflask.py should be like something below for it to work
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run(host='0.0.0.0', port=5901)
#app.run()
Might I suggest trying something like pyngrok to programmatically manage an ngrok tunnel for you? Full disclosure, I am the developer of it. Flask example here, but it's as easy as installing pyngrok:
pip install pyngrok
and using it:
from pyngrok import ngrok
# <NgrokTunnel: "http://<public_sub>.ngrok.io" -> "http://localhost:5000">
http_url = ngrok.connect(5000)
I have a Django web server on a VirtualBox/Vagrant machine running "bento/centos-6.7-i386".
I have followed this guide to create a Django project: https://docs.djangoproject.com/en/dev/intro/tutorial01/
I have a web server running at http://127.0.0.1:8000/ inside my guest machine. This is the first time I am running a Django web server. It is supposed to be a hello world app.
How can I access this web application from my host browser?
I tried adding this line - config.vm.network "private_network", ip: "55.55.55.5" in the vagrant file and then tried to run the python manage.py runserver 0.0.0.0:80 command as per 1 of the solutions explained in previous discussions by others but I couldn't access the site from my host browser using 55.55.55.5:8000.
How can I access the web server from my browser?
Following given is my Vagrant File:
# -- mode: ruby --
# vi: set ft=ruby :
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "bento/centos-6.7-i386"
config.vm.network "forwarded_port", guest: 8000, host: 8000
config.vm.network "forwarded_port", guest: 8080, host: 8080
config.vm.network "forwarded_port", guest: 5000, host: 5000
config.vm.network "private_network", ip: "10.10.10.10"
end
You're forwarding port 8000 on the guest to 8000 on the host. Try:
python manage.py runserver 0:8000
Then in your browser visit: http://localhost:8000
That'll leave port 80 free if you end up wanting to run a web server for testing as well. Good luck!
if you are using below line in your Vagrantfile for port forwarding
config.vm.network "forwarded_port", guest: 8000, host: 8000
It means you will be able to access your guest application which running at port 8000 in your host browser at port 8000. so you will be able access by hitting http://127.0.0.1:8000 or http://localhost:8000 in your host.
why you are forcing your app to run on 0.0.0.0 ? .
it is not required , or if you want to access with guest IP address then there is no sense to use port forwarding.
if you changed this configuration in Vagrantfile after provision then don`t forget to reload
vagrant reload
I got a problem with Django and port forwarding insider VB.
Django doesn't allow external hosts to access it.
So change the start command to
python3 ./manage.py runserver 0.0.0.0:8000
and everything worked
My use case:
We need to run a watir-webdriver script in headless mode and our dev machines run Windows.
The gist of our problem:
I can stand up the python server inside the container, but I can't connect to it at its expected location from the host: http://192.168.59.103:8084.
The architecture:
A ruby script that "does something useful and prints the output to the console" and a basic python server that imports os and then executes os.system('ruby ourrubyscript.rb') inside our index route. We also brought in flask for api routing and flask.cors to eliminate potential cross origin issues.
Local test (on Host):
running "python server.py" in our host workspace stands up a python server on port 5000. Routing to it from a browser executes our route and prints the expected output to the console.
server.py
from flask import Flask
from flask import request
from flask.ext.cors import CORS
import os
app = Flask(__name__)
CORS(app, resources={r'/': {"origins": "*"}}, headers='Content-Type')
app.config['CORS_HEADERS'] = 'Content-Type'
#app.route('/')
def index():
return "<h1>Hello Stupid</h1>"
#app.route('/ruby/test', methods=['GET'])
def runRubyScript():
return os.system("ruby script.rb")
if __name__ == "__main__":
app.run()
When I nav to localhost:5000, "Hello Stupid" prints to my screen.
When I route to localhost:5000/ruby/test, our script runs and that script prints to my console.
Procedure to move this to docker
We pulled latest centos and installed wget, xvfb, git, ruby, python, pip, flask, flask-cors, and firefox; committed that to a local image named "webdev."
Then gem installed headless and installed phantomjs to $PATH
We then cloned our src repository to "/opt/testapp" in the container. This repository contains our "server.py" file and a "script.rb" file.
docker#boot2docker:~$ docker run -d -p 5000:5000 --name wd webdev python /opt/testapp/server.py
So, I left my boot2docker-vm bound to private ip 192.168.59.103, and I can confirm that this ip is valid by navigating to a different port that is running a different container; however, when I navigate to 5000, I get an ERR_CONNECTION_REFUSED. I had an almost "AHA!!" moment thinking that iptables had the port locked down by default and we needed to go open internal port 5000 in order to map it out to the vm but then I found that the centos image does not have iptables (or firewalld since this is CentOS7) installed by default. When that approach turned out to be incorrect, I decided to post to see if anyone might be able to assist here because I am out of ideas.
So I have figured out why this is not exposed to the host environment and this makes perfect sense.
In NAT mode, the virtual machine gets assigned a private static ip address: 192.168.59.103 (that is...the virtual machine gets assigned that IP)
Each container stands up with 2 adapters: a loopback and an externally facing virtual private bridge accessible to the vm.
When I stand up my server on port 5000, it binds directly to loopback inside the container and is inaccessible to the virtual machine.
Removing the localhost binding from the service and allowing it to
bind to the default gateway 0.0.0.0:5000
causes the service to listen on all adapters and allows communications
between the vm and the container's external adapter through the
virtual private bridge that gets created when the container stands.
For some reason, switching my virtual machine to run in Bridged mode against my NIC is causing the boot2docker-vm to crash on start....so I'm relegated to NAT for the time being until I can figure out how to switch it properly.
[Edit 1 (related to bridging)]
Bridge mode seems to currently be unsupported in boot2docker as of at least October 8, 2014. b2d expects a NAT adapter for ssh bootstrapping and the host adapter for container<->container socket access.
The current, unsupported, undocumented workaround to expose a container to hosts on a network is to add a third network interface to VirtualBox and bridge with it.
[Edit 2 (example server running against default gateway)]
Here is an example of a flask server that attaches to all interfaces:
Note that the only Δ between the server above and the server below is the final line of the configuration.
app.run()
needs to become
app.run(host='0.0.0.0')
from flask import Flask
from flask import request
from flask.ext.cors import CORS
import os
app = Flask(__name__)
CORS(app, resources={r'/': {"origins": "*"}}, headers='Content-Type')
app.config['CORS_HEADERS'] = 'Content-Type'
#app.route('/')
def index():
return "<h1>Hello Stupid</h1>"
#app.route('/ruby/test', methods=['GET'])
def runRubyScript():
return os.system("ruby script.rb")
if __name__ == "__main__":
app.run(host='0.0.0.0')