flask url_for behind a reverse proxy - flask

I have a flask application running on a server (192.168.1.1:8080) located behind a reverse proxy. Let's say, the url https://foo.bar.com/myapp point to my flask app, i.e. to 192.168.1.1:8080.
I am in trouble with the url_for flask function, as it returns something like http://192.168.1.1:8080/blabla (giving blabla as parameter).
How to proceed so that url_for returns https://foo.bar.com/myapp/blabla instead ?
In fact, my application uses a CAS authentication system. So that the ticket gets validate by the CAS server, I need to provide an URL of the shape https://foo.bar.com/....
Any help would be appreciate.

I found a solution using ProxyFix from werkzeug :
from werkzeug.middleware.proxy_fix import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app, x_host=1)

Related

Configuring a Flask application running on gunicorn to run behind a file path [duplicate]

This question already has answers here:
Python - Flask Default Route possible?
(4 answers)
Closed 7 months ago.
I am trying to configure a Flask application hosted with gunicorn to run behind a file path.
The current app is designed to run at www.example.com, but I would like to configure it to run at example.com/foo/bar
The difficulty I am having is that I can't seem to get the requests to be sent to the application. It currently works fine if you go to example.com, but going to example.com/foo/bar results in nothing. Everything is done through AWS. The networking has been setup to pass example.com/foo/bar requests to the server. The Flask init is as follows:
import os
from functools import wraps
import requests
from flask import Flask, render_template, make_response, redirect, Response, g
app = Flask(__name__)
app.config['VERSION'] = '3.7.2'
app.config['SERVER_ADDRESS'] = os.environ.get('SERVER_ADDRESS', 'https://example.com/')
app.config['APPLICATION_ROOT'] = '/foo/bar/'
#app.before_request
def set_server_address():
g.server_address = app.config['SERVER_ADDRESS']
#app.route('/')
def index(*args, **kwargs):
return redirect('/app/example')
When I check the logs after visiting example.com/foo/bar, there is no traffic. Any light which could be shed on this would be very much appreciated.
You can solve this problem by adding the /foo/bar to your flask route.
#app.route('/foo/bar')
def make_homepage():
return 'success'
But it's not best practice because each time the response will be as a redirect and with high traffic it's could be pretty resource intensive, so i will recommend to you to check this question:
Python - Flask Default Route possible?

Routing Flask application API GET requests through pythonanywhere proxy

I've been stuck for a couple of days now trying to get a little football fixtures website hosted on pythonanywhere.com as a first personal project using FLASK
The issue I seem to have run into is that I need to route API calls through the pythonanywhere proxy (proxy.server:3128) but I've no idea how to configure this (I'm a beginner tbh)
Any help to point me in the right direction would be much appreciated
Some sample code below as an example of a request I'm trying to make (these work fine when hosted locally, but pythonanywhere requires the proxy routing for http requests)
from flask import Flask, request
import http.client
connection = http.client.HTTPConnection('api.football-data.org')
def getCompetitions():
print ("running getCompetitions")
connection.request('GET', '/v2/competitions/', None, headers )
response = json.loads(connection.getresponse().read().decode())
return response
competitions = getCompetitions()
Found it! Actually not too bad, just I'm a noob!
I needed to use the .set_tunnel function related to python's http.client function to do the routing through the proxy
Documentation here: https://docs.python.org/3/library/http.client.html
Usage for this example:
connection = http.client.HTTPSConnection("proxy.server", 3128)
connection.set_tunnel("api.football-data.org")
Hopefully this helps someone!

route to Flask encounters 404

I'm following the steps in https://github.com/twilio/starter-python
Access to http://localhost:5000/ can get expected response though http://localhost:5000/hello just gets 404.
Here part of the code
from flask import Flask, Response, request, render_template
from twilio.twiml.voice_response import VoiceResponse
from twilio.rest import Client
#app.route('/hello', methods=['GET', 'POST'])
def hello():
response = VoiceResponse()
response.say('Hello there! You have successfully configured a web hook.')
response.say('Good luck on your Twilio quest!', voice='woman')
return Response(str(response), mimetype='text/xml')
I actually run the example on there python app.py, the only modification is three system environment variables the app needed.
I can't figure what could cause that. Could someone give a clue?
I had the same problem before. But mine was solved as some other application was running on port 5000. Try changing the port and I think it should work.
Try referring to this stack overflow

How to link Django and React URLs to perform actions?

In Django, I have my login URL set to 'api/auth/login'. When given a username and password, it will log that user in. Running 'python manage.py runserver', it will put that URL at 'http://127.0.0.1:8000/api/auth/login'
However, my React project, when running 'yarn start' is at 'http://localhost:3000/' and giving it the extension 'api/auth/login', the url it attempts is 'http://localhost:3000/api/auth/login'.
This does not work, but if I replace the URL extension with 'http://127.0.0.1:8000/api/auth/login', the login works as expected.
How can I have the URLs work with my React app? Or is this not something that necessarily needs to be fixed? I do plan to host this project somewhere and am not yet sure how the URLs will work out..
One option is to set proxy in the package.json.
Second option is to set axois baseURL:
// add in your code before main component definition
// for example in App.js
import axios from "axios";
axios.defaults.baseURL = "http://127.0.0.1:8000";
I'm preferring the second approach. For doing production build it can be easily overwritten with an environment variable.
import axios from "axios";
axios.defaults.baseURL = REACT_APP_SERVER_URL
Remember to set the CORS headers in the Django server (I'm working on tutorial with an example how to do this).
You are hosting react application on another port that's why when you put a request without mentioning host, it gets appended to your current host i.e. 127.0.0.1:3000. I suggest you write "proxy": '127. 0.0.1:8000' in your package.json (refer https://create-react-app.dev/docs/proxying-api-requests-in-development/) and restart your react server or use full url of django server i.e. 127.0.0.1:8000/

Proper URL routing configuration for Flask with proxy pass

I'm struggling to find the proper way to setup my flask routes when moving my app to being hosted in a subdirectory. I've read a bunch of great answers on this subject, most notably this answer on adding a prefix to all routes. However, I think my situation is slightly different. I want to ONLY prefix the URLs I generate with url_for, not respond to those URLs. Is there a way to do this?
For example, assume my flask app is hosted at http://www.acme.com/tools/. The main acme.com domain is setup with a proxy pass to pass all requests from /tools/* to my app. So, my app only sees requests like /, /product_1/ even though the full URL is http://www.acme.com/tools/product_/, etc. So, my app.route rules can use / as the base route. The problem is I use url_for everywhere and I want the urls generated to be the full url like /tools/product_1, not /product_1. Is there a way to achieve this?
I've tried using blueprints but those will make the #app.route and url_for respond to /tools/xyz. Is there a more simple solution to this issue or is this a non-standard way to handle this issue?
I would take a look at this snippet: http://flask.pocoo.org/snippets/35/
I'm not sure I love the idea of modifying your WSGI environment as the only solution to this problem. You can always wrap url_for. (note that this won't work for _external=True)
def my_url_for(*args, **kwargs):
return '/tools' + url_for(*args, **kwargs)
Be sure to set your APPLICATION_ROOT to /tools so that cookies are only accessible from the app.
I found a different way to handle this without having to provide a wrapper for url_for. I'm using a custom routing rule to append the prefix. This means none of the app.route decorator calls have to be changed and all calls to url_for will automatically get the prefix added. Are there any caveats I'm missing by overriding the url_rule_class?
Add the following to your __init__.py after setting up your app.
from werkzeug.routing import Rule
class PrefixRule(Rule):
def build(self, *args, **kwargs):
domain_part, url = super(PrefixRule, self).build(*args, **kwargs)
return domain_part, u'%s%s' % (app.config['PREFIX'], url)
app.url_rule_class = PrefixRule