route defined in flask returns 404 - nginx

I have a simple Flask script that has different routes defined with #app.route. The app is running through gunicorn on a nginx server.
The problem occurs when trying to access any route. Except for base url ( "/") , all url return an nginx 404 page. The app runs on venv and I have no idea on how to configure nginx so that they can be served.
I don't know whether to update nginx.conf, default site or something else.
I tried looking for nginx configuration for flask but found no appropriate resource.
The app looks like this
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return "<h1 style='color:blue'>Hello There!</h1>"
#app.route("/test")
def test():
return "Test"
if __name__ == "__main__":
app.run(host='0.0.0.0')
I excpect /test to open, same way it opens on development server, but returns 404 on nginx.

Related

Can't access the fastapi page using the public ipv4 address of the deployed aws ec2 instance with uvicorn running service

I was testing a simple fastapi backend by deploying it on aws ec2 instance. The service runs fine in the default port 8000 in the local machine. But as I ran the script on the ec2 instance with
uvicorn main:app --reload it ran just fine with following return
INFO: Will watch for changes in these directories: ['file/path']
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [4698] using StatReload
INFO: Started server process [4700]
INFO: Waiting for application startup.
INFO: Application startup complete.
Then in the ec2 security group configuration, the TCP for 8000 port was allowed as shown in the below image.
ec2 security group port detail
Then to test and access the service I opened the public ipv4 address with port address as https://ec2-public-ipv4-ip:8000/ in chrome.
But there is no response whatsoever.
The webpage is as below
result webpage
The error in the console is as below
VM697:6747 crbug/1173575, non-JS module files deprecated.
(anonymous) # VM697:6747
The fastapi main file contains :->
from fastapi import FastAPI, Form, Depends
from fastapi.middleware.cors import CORSMiddleware
from fastapi.encoders import jsonable_encoder
import joblib
import numpy as np
import os
from own.preprocess import Preprocess
import sklearn
col_data = joblib.load("col_bool_mod.z")
app = FastAPI()
#app.get("/predict")
async def test():
return jsonable_encoder(col_data)
#app.post("/predict")
async def provide(data: list):
print(data)
output = main(data)
return output
def predict_main(df):
num_folds = len(os.listdir("./models/"))
result_li = []
for fold in range(num_folds):
print(f"predicting for fold {fold} / {num_folds}")
model = joblib.load(f"./models/tabnet/{fold}_tabnet_reg_adam/{fold}_model.z")
result = model.predict(df)
print(result)
result_li.append(result)
return np.mean(result_li)
def main(data):
df = Preprocess(data)
res = predict_main(df)
print(res)
return {"value": f"{np.float64(res).item():.3f}" if res >=0 else f"{np.float64(0).item()}"}
The service runs fine with same steps in the react js frontend using port 3000 but the fastapi on 8000 is somehow not working.
Thank You for Your Patience
I wanted to retrieve the basic api reponses from the fastapi-uvicorn server deployed in an aws ec2 instance. But there is no response with 8000 port open and ec2 access on local ipv4 ip address.
One way the problem is fixed is by assigning public ipv4 address followed by port 3000 in the CORS origin. But the issue is to hide the get request data on the browser that is accessed by 8000 port.

How do I deploy Apache-Airflow via uWSGI and nginx?

I'm trying to deploy airflow in a production environment on a server running nginx and uWSGI.
I've searched the web and found instructions on installing airflow behind a reverse proxy, but those instructions only have nginx config examples. However, due to the permissions, I can't change the nginx.conf itself and have to solve it via uswsgi.
My folder structure is:
project_folder
|_airflow
|_airflow.cfg
|_webserver_config.py
|_wsgi.py
|_env
|_start
|_stop
|_uwsgi.ini
My path/to/myproject/uwsgi.ini file is configured as follows:
[uwsgi]
master = True
http-socket = 127.0.0.1:9999
virtualenv = /path/to/myproject/env/
daemonize = /path/to/myproject/uwsgi.log
pidfile = /path/to/myproject/tmp/myapp.pid
workers = 2
threads = 2
# adjust the following to point to your project
wsgi-file = /path/to/myproject/airflow/wsgi.py
touch-reload = /path/to/myproject/airflow/wsgi.py
and currently the /path/to/myproject/airflow/wsgi.py looks as follows:
def application(env, start_response):
start_response('200 OK', [('Content-Type','text/html')])
return [b'Hello World!']
I'm assuming I have to somehow call the airflow flask app from the wsgi.py file (perhaps by also changing some reverse proxy fix configs, since I'm behind SSL), but I'm stuck; what do I have to configure?
Will this procedure then be identical for the workers and scheduler?

How to redirect HTTPS traffic to local HTTP server using mitmproxy?

I am trying to setup mitmproxy so that I can make a request from my browser to https://{my-domain} and have it return a response from my local server running at http://localhost:3000 instead, but I cannot get the https request to reach my local server. I see the debugging statements from mitmproxy. Also, I can get it working for http traffic, but not for https.
I read the mitmproxy addon docs and api docs
I've installed the cert and I can monitor https through the proxy.
I'm using Mitmproxy: 4.0.4 and Python: 3.7.4
This is my addon (local-redirect.py) and how I run mitmproxy:
from mitmproxy import ctx
import mitmproxy.http
class LocalRedirect:
def __init__(self):
print('Loaded redirect addon')
def request(self, flow: mitmproxy.http.HTTPFlow):
if 'my-actual-domain-here' in flow.request.pretty_host:
ctx.log.info("pretty host is: %s" % flow.request.pretty_host)
flow.request.host = "localhost"
flow.request.port = 3000
flow.request.scheme = 'http'
addons = [
LocalRedirect()
]
$ mitmdump -s local-redirect.py | grep pretty
When I visit the url form my server, I see the logging statement, but my browser hangs on the request and there is no request made to my local server.
The above addon was fine, however my local server did not support HTTP2.
Using the --no-http2 option was a quick fix:
mitmproxy -s local-redirect.py --no-http2 --view-filter localhost
or
mitmdump -s local-redirect.py --no-http2 localhost

How to host multiple flask apps under a single domain hosted on nginx?

What I am trying to achieve:
I have an nginx web server hosting mydomain.com. When someone types my domain.com into their client I would like my server to serve index.html from /var/www/mydomain/ When they type mydomain.com/flaskapp1 they should see flaskapp1. When they type mydomain.com/flaskapp2 they should see flaskapp2.
I have managed to get one or the other flask apps served using the tutorial here http://www.markjberger.com/flask-with-virtualenv-uwsgi-nginx/ but when trying to implement serving two separate flask apps I run into difficulty. Instead of seeing the flask app I get a 404 message when I try to access either of the flask apps with mydomain.co.uk/flaskapp or mydomain.co.uk/flaskapp2 in a browser.
This is what I have so far:
cat /etc/nginx/sites-available/mydomain.co.uk
server {
listen 80;
server_name www.mydomain.co.uk mydomain.co.uk;
location / {
root /var/www/html/;
index index.html index.htm;
}
location /flaskapp {
include uwsgi_params;
uwsgi_pass unix:/tmp/flaskapp.sock;
}
location /flaskapp2 {
include uwsgi_params;
uwsgi_pass unix:/tmp/flaskapp2.sock;
}
}
The above conf file has been sim linked into /etc/nginx/sites-enabled.
cat /etc/uwsgi/apps-available/flaskapp.ini
[uwsgi]
vhost = true
socket = /tmp/flaskapp.sock
venv = /var/www/flaskapp/venv
chdir = /var/www/flaskapp
module = flaskapp
callable = app
cat /etc/uwsgi/apps-available/flaskapp2.ini
[uwsgi]
vhost = true
socket = /tmp/flaskapp2.sock
venv = /var/www/flaskapp2/venv
chdir = /var/www/flaskapp2
module = flaskapp2
callable = app
Both .ini files have been symlinked into /etc/uwsgi/apps-enabled. UWSGI restarts fine without any issues and is up and running. Both flaskapp.sock and flaskapp2.sock are owned by www-data
cat /var/www/flaskapp/flaskapp.py
from flask import Flask
app = Flask(__name__)
#app.route('/')
def hello_world():
return 'Hello World from flaskapp1!'
if __name__ == '__main__':
app.run(host='0.0.0.0')
cat /var/www/flaskapp2/flaskapp2.py
from flask import Flask
app = Flask(__name__)
#app.route('/')
def hello_world():
return 'Hello World from flaskapp2!'
if __name__ == '__main__':
app.run(host='0.0.0.0')
cat /var/www/mydomain.co.uk/index.html
<!DOCTYPE html>
<html>
<body>
<h1>mydomain.co.uk</h1>
<p>This is the index page of my domain.co.uk</p>
</body>
</html>
Both virtual environments have flask installed and will run the flask apps using the development server.
I hope it's something simple that I've missed.
Looking at the uwsgi documentation for NGINX here.
Specifically:
Unfortunately nginx is not able to rewrite PATH_INFO accordingly to
SCRIPT_NAME. For such reason you need to instruct uWSGI to map
specific apps in the so called “mountpoint” and rewrite SCRIPT_NAME
and PATH_INFO automatically:
Changing my flaskapp.ini and flaskapp2.ini files to contain the mount points for the apps and turning on the manage-script-name variable has worked.
cat /etc/uwsgi/apps-available/flaskapp.ini
[uwsgi]
vhost = true
socket = /tmp/flaskapp.sock
venv = /var/www/flaskapp/venv
chdir = /var/www/flaskapp
module = flaskapp
callable = app
mount = /flaskapp=flaskapp.py
manage-script-name = true
cat /etc/uwsgi/apps-available/flaskapp2.ini
[uwsgi]
vhost = true
socket = /tmp/flaskapp2.sock
venv = /var/www/flaskapp2/venv
chdir = /var/www/flaskapp2
module = flaskapp2
callable = app
mount = /flaskapp2=flaskapp2.py
manage-script-name = true
And now both flask apps are running via uwsgi through nginx as required.
The problem is here: both flask apps have no idea that they were served from subdirectory in your domain. Nginx is passing full URL to them, not URL relative to that directory, so every URL is dispatched relative to root. Let's see that in example:
Assume that you have 3 views in your flaskapp, served on urls /one/, /two/ and /three/. So when you're trying to access view on URL /one/, you are typing address: http://yourdomain.com/flaskapp/one/. Flask will receive from nginx URL /flaskapp/one/ but there is no such view in that app, so it will send 404 in response.
What you can do is inform each flaskapp that they aren't served on domain root, but on particular subdirectory. You can achieve this by sending SCRIPT_NAME uwsgi_param with subdirectory location in value, so your nginx config will have:
location /flaskapp {
include uwsgi_params;
uwsgi_pass unix:/tmp/flaskapp.sock;
uwsgi_param SCRIPT_NAME /flaskapp;
}
location /flaskapp2 {
include uwsgi_params;
uwsgi_pass unix:/tmp/flaskapp2.sock;
uwsgi_param SCRIPT_NAME /flaskapp2;
}
Adding the mounting point worked for me.
/etc/uwsgi/apps-available/flaskapp.ini
callable = app
mount = /flaskapp=/var/www/flaskapp
/etc/uwsgi/apps-available/flaskapp2.ini
callable = app
mount = /flaskapp2=/var/www/flaskapp2
Source https://neginfinity.bitbucket.io/2017/09/hosting-multiple-flask-applications-in-nginx.html

tornadoweb gzip=True not working under supervisord and nginx

While working with tornado, I've discovered gzip=True feature, which works fine while running application from command line, below settings:
define("port", default=settings.LISTEN_PORT, help="run on the given port", type=int)
define("debug", default=True, help="run in debug mode", type=bool)
define("dont_optimize_static_content", default=False,
help="Don't combine static resources", type=bool)
define("dont_embed_static_url", default=False,
help="Don't put embed the static URL in static_url()", type=bool)
tornado.options.parse_command_line()
tornado.options.options['log_file_prefix'].set('/var/log/tmp.log')
app_settings = dict(
template_path=os.path.join(os.path.dirname(__file__), "templates"),
static_path=os.path.join(os.path.dirname(__file__), "static"),
xsrf_cookies=False,
gzip=True,
debug=True,
)
However, deploying app with supervisord/nginx responses from tornado servers are not gziped.
[program:app-8001]
command=python /var/app/server/app.py --port=8001 --logging=debug ----dont_optimize_static_content=False
directory=/var/app/server/
stderr_logfile = /var/log/app-stderr.log
stderr_logfile_backups=10
stdout_logfile = /var/log/app-stdout.log
stdout_logfile_backups=10
process_name=%(program_name)s
loglevel=debug
Any ideas what am i doing wrong?
By default nginx doesn't do HTTP/1.1 requests when it proxies requests to Tornado (or anything for that matter). Tornado requires HTTP/1.1 support for returning gzip'ed content.
Significant code fragment from web.py
def __init__(self, request):
self._gzipping = request.supports_http_1_1() and \
"gzip" in request.headers.get("Accept-Encoding", "")
It should be overrideable by adding the following to your config file - however it doesn't work on my instance.
proxy_http_version 1.1;

Resources