Get host and port for Heroku app - python

I'm trying to get a Crossbar.io app running on Heroku. Crossbar.io requires you to put the app's host in a config file that's used to launch the app. I've tried the following:
my-app-name.herokuapp.com: No dice. I imagine Heroku does some fancy redirection internally that prevents this from working.
$HOSTNAME: running a script that outputs the HOSTNAME and using the result in the config file doesn't work either. The HOSTNAME is a GUID that contains no useful information.
IP: I tried getting the external IP of the app, but no luck. The IP changes each time I start the app.
Is there an established way to do this on Heroku?
Also the config requires a port and Heroku seems to assign these dynamically. Any way to access the port as well (ideally before the app runs)

For the host use 0.0.0.0. For the port number it's slightly more complicated...
When it creates a web dynamo Heroku sets a PORT environment variable with the dynamo's port. To set this in crossbar you need to create a script that reads that variable and writes it into your config wherever the port is requested. Then you make sure that the script returns 0 on exit and put the following in your Procfile:
web: ./your_config_helper_script && crossbar start
That runs your script first (which should get your config file ready) before running crossbar

Related

Flask_oidc gives `Errno 99 Cannot assign requested address` when run in Docker container

Goal:
Use OIDC from a Flask app running in a Docker container.
Background:
I'm building a web application with Flask and want to use Keycloak to provide access. For this I use the Python library flask_oidc.
All services are run locally with a docker-compose file:
Gunicorn that runs the Flask application (port 5000)
Keycloak (port 8080)
I followed the example of https://gist.github.com/thomasdarimont/145dc9aa857b831ff2eff221b79d179a and even reduced my app to just this.
Problem:
Start all services
Navigate to the service that requires login (/private in the example)
The user is rerouted to the Keycloud server prompting to log in.
The user logs in.
Keycloak routes the user back to the app (/oidc_callback)
!!! The Flask app crashes with an OSError: [Errno 99] Cannot assign requested address error.
This is caused deep down in flask_oidc > oauth2client > httplib2 when trying to connect to the Keycloak server.
What I think is happening is that the library tries to open a connection with the Keycloak server, but tries to bind this to localhost. This probably fails, since inside the Docker container the applications are bound to 0.0.0.0.
What I tried:
[WORKS] Run the Gunicorn/Flask app outside of a container, and run the Keylcoak inside a container.
This shows (to me) that all my settings and the code are fine, but that the problem is somewhere in the interaction between Docker<-->flask_oidc+.
Question:
Can anyone explain this? I really hope that someone has a working setup (Flask inside docker with flask_oidc), and is willing to share this.
UPDATE [5-12-2018]
I think I figured it out. I used PyOIDC to manually go through all the steps and be able to debug.
When running both services in Docker on your own computer (localhost) you get a conflict:
Users go to localhost:8080 to find Keycloak and localhost:5000 to find the App.
The Flask app runs inside the container, and localhost doesn't resolve to the host but rather to itself inside the container.
You can let Flask connect to http://keycloak/ using the network in the container, but then it returns all the configuration under this domain. Which is bad, because to the outside world it should be localhost:8080.
Now, if you actually have domain names (for example keycloak.awesome.app and app.awesome.app) I think it'll just work fine, since it'll use an outside DNS to resolve it to an IP address, which is the correct machine.
Bonus: PyOIDC can retrieve the provider configuration from the Keycloak, so no more manual typing for this. Yay!
New setup
For local development I decided to make a little setup as follows:
(1) Add to /etc/hosts:
127.0.0.1 keycloak.dev.local
127.0.0.1 app.dev.local
(2) Add to your Flask service in the docker-compose.yml:
extra_hosts: #host.docker.internal is not accepted.
- "keycloak.dev.local:<YOUR IP ADRESS>"
- "app.dev.local:<YOUR IP ADRESS>"
(=) Now, both you and the Flask application can access keycloak.dev.local and can proper reponses!
Note that I would still prefer a nicer solution. This setup fails as soon as my ip address changes.
flask-oidc gets token endpoint configuration from the client secrets file.
I managed to make it work by making the following changes:
Created a docker network for the flask app and keycloak containers;
Edited the attributes userinfo_uri, token_uri and token_introspection_uri, replacing the hostname with the keycloak container hostname (i'm using docker-compose, in this case the keycloak container hostname is the service name).
Example:
{
"web": {
"auth_uri": "http://localhost:8080/auth/realms/REMOVED/protocol/openid-connect/auth",
"client_id": "flask-client",
"client_secret": "REMOVED",
"redirect_uris": ["http://localhost:5000/oidc_callback"],
"userinfo_uri": "http://keycloak:8080/auth/realms/REMOVED/protocol/openid-connect/userinfo",
"token_uri": "http://keycloak:8080/auth/realms/REMOVED/protocol/openid-connect/token",
"token_introspection_uri": "http://keycloak:8080/auth/realms/REMOVED/protocol/openid-connect/token/introspect"
}
}
Now it connects through the docker network to exchange token info.

Flask app on plesk/apache server - how to change port?

I'm new to setting up a server for python apps, slowly getting my head round all the tools and config options.
I'd like to configure a testing instance on an existing server that has plesk and apache installed. I managed to set up the python environment, virtualenv, the flask app inclusive database and run it successfully on http://domain.test:5000 however I'd need to remove the port number from the domain.
Gunicorn seems to be the tool for that, however I'm not sure how to go about it as plesk is apparently installed on port 80 - so is there any way to get this configured on that server with some port hiding/masking/redirect or do I need to move to a standalone server?
Additionally I'd like to add a ssl certificate to that domain but one step at the time...
The method run on a Flask application takes a keyword argument port:
from flask import Flask
app = Flask(__name__)
app.run(port=80)
Of course you'll need root privileges to run on port 80

Error accessing my webpage from network

I've just started learning network developing using Flask. According to its official tutorial:
Externally Visible Server
If you run the server you will notice that the server is only
accessible from your own computer, not from any other in the network.
This is the default because in debugging mode a user of the
application can execute arbitrary Python code on your computer.
If you have the debugger disabled or trust the users on your network,
you can make the server publicly available simply by adding
--host=0.0.0.0 to the command line:
flask run --host=0.0.0.0
This tells your operating system to listen on all public IPs.
However, when I try to access 0.0.0.0:5000 on another device, I got an error: ERR_CONNECTION_REFUSE. In fact, I think this behavior is reasonable, since people all around world can use 0.0.0.0:5000 for different testing purposes, but isn't the tutorial implying that adding --host=0.0.0.0 can make my webpage "accessible not only from your own computer, but also from any other in the network"?
So, my question is:
What does adding --host=0.0.0.0 do?
How can I access my webpage on device B while the server is running on device A?
You don't access the Flask server on another computer by going to 0.0.0.0:5000. Instead, you need to put in the IP address of the computer that it is running on.
For example, if you are developing on a computer that has IP address 10.10.0.1, you can run the server like so:
flask run --host=0.0.0.0 --port=5000
This will start the server (on 10.10.0.1:5000) and listen for any connections from anywhere. Now your other device (say, on 10.10.0.2) can access that server by going to http://10.10.0.1:5000 in the browser.
If you don't have the host=0.0.0.0, the server on 10.10.0.1 will only listen for connections from itself (localhost). By adding that parameter, you are telling it to listen from connections external to itself.

"Unable to bind localhost:8000" error while running sample application in google app engine

I have just installed GAE launcher and am trying to run a sample application to make sure it works and I am getting the below error.
raise BindError('Unable to bind %s:%s' % self.bind_addr)
google.appengine.tools.devappserver2.wsgi_server.BindError: Unable to bind localhost:8000
2014-03-24 10:54:54 (Process exited with code 1)
I am trying to run the python version of the app with python 2.7 and am using windows 8.1 operating system. I did not create any files for the app, I just created a new application and am trying to run it in localhost.
Can someone please tell me what this error means and how to fix it?
The app server starts two servers: one for your application, the other for development console.
Change the ip address for the development console with:
dev_appserver.py --admin_port=9000
Another process is already bound to port 8000. Use netstat -an or netstat -anb or similar to investigate. It may be another instance of your development server.
Edit: If port 8000 is really occupied, Command-line arguments in the The Python Development Server says you can append --admin_port to change the 8000 to another free port.
For me, I have to use both --admin-port and --port
dev_appserver.py --admin_port=9000 --port=9999 app.yaml
I hope it might help others using PyCharm to understand where to set the admin port to something different than 8000.
Go to your "Run/Debug configurations" and in the configuration tab, add the following into "additional options":
--admin_port=9000

How do I access my django app running on Amazon ec2?

So, I have looked around stack overflow + other sites, but havent been able to solve this problem: hence posting this question!
I have recently started learning django... and am now trying to run it on ec2.
I have an ec2 instance of this format: ec2-xx-xxx-xx-xxx.us-west-2.compute.amazonaws.com on which I have a django app running. I changed the security group of this instance to allow http port 80 connections.
I did try to run it the django app the following ways: python manage.py runserver 0.0.0.0:8000 and python manage.py runserver ec2-xx-xxx-xx-xxx.us-west-2.compute.amazonaws.com:8000 and that doesnt seem to be helping either!
To make sure that there is nothing faulty from django's side, I opened another terminal window and ssh'ed into the instance and did a curl GET request to localhost:8000/admin which went through successfully.
Where am I going wrong? Will appreciate any help!
You are running the app on port 8000, when that port isn't open on the instance (you only opened port 80).
So either close port 80 and open port 8000 from the security group, or run your app on port 80.
Running any application on a port that is less than 1024 requires root privileges; so if you try to do python manage.py runserver 0.0.0.0:80 as a normal user, you'll get an error.
Instead of doing sudo python manage.py runserver 0.0.0.0:80, you have a few options:
Run a pre-configured AMI image for django (like this one from bitnami).
Configure a front end server to listen on port 80, and then proxy requests to your django application. The common stack here is nginx + gunicorn + supervisor, and this blog post explains how to set that up (along with a virtual environment which is always a good habit to get into).
Make sure to include your IPv4 Public IP address in the ALLOWED_HOSTS section in Django project/app/settings.py script...

Categories