I am try to deploy flask on a sub directory on my website, this script is super light weight and doesn't need (actually it can't) to roll into the main project. How ever when I go to the end point, I get a 404 error from flask (can confirm that it is flask because the log shows activity). I am passing uwsgi_param SCRIPT_NAME /upload; and uwsgi_modifier1 30; in my nginx config file, but that doesn't seem to work. How can I get uwsgi to serve my flask application on an nginx sub location (subdir)?
Here is my nginx config (the /upload location is where the trouble is):
upstream django {
server app0.api.xyz.com:9002;
}
server {
listen 443;
ssl on;
ssl_certificate /etc/nginx/ssl/cert_chain.crt;
ssl_certificate_key /etc/nginx/ssl/api_xyz.key;
charset utf-8;
server_name dev.api.xyz.com;
location / {
uwsgi_pass django;
include /etc/nginx/uwsgi_params;
}
location /media {
alias /var/xyzdata;
}
location /upload {
include /etc/nginx/uwsgi_params;
uwsgi_pass unix:/var/sockets/upload.sock;
uwsgi_param SCRIPT_NAME /upload;
uwsgi_modifier1 30;
}
}
my uwsgi.ini file:
[uwsgi]
chdir = /home/ubuntu/uploadFlask
module = images
callable = app
socket = /var/sockets/upload.sock
master = true
processes = 10
vacuum = true
uid = www-data
gid = www-data
daemonize = /var/log/uploads/error.log
and finally my entire flask app:
import os
from flask import Flask, request, redirect, url_for,Response, jsonify
from werkzeug import secure_filename
import time
UPLOAD_FOLDER = '/var/xyzdata'
ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'])
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['DEBUG'] = True
#app.route('/<user>', methods=['POST'])
def upload_file(user):
file = request.files['file']
if file:
file_id = str(time.time()).replace('.','_')
filename = "{0}/images/{1}.jpg".format(user, file_id)
path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
d = os.path.dirname(path)
if not os.path.exists(d):
os.makedirs(d)
file.save(path)
return jsonify(physical_path=path, virtual_path=filename,
id=file_id)
#app.route('/delete/<user>/<id>/', methods=['POST'])
def delete_file(user, id):
pass
the point of this script is to upload images to my static server. My actual application sits on a separate server and thats why this can't sit there.
Basically what i want is to be able to go to dev.api.xyz.com/upload/123/ and hit upload_file. I'm expecting a 405 error in the browser, because it is restricted to POST. But I am getting a 404 error. Here is a sample output from the flask/uwsgi log:
[pid: 27900|app: 0|req: 4/5] 50.199.33.84 () {40 vars in 669 bytes} [Wed Jul 1 01:03:51 2015] GET /upload/things#things.com => generated 233 bytes in 0 msecs (HTTP/1.1 404) 2 headers in 72 bytes (1 switches on core 0)
So flask is getting hit but the url matching is not working. Thanks in advance for your help.
The best solution I've found so far would be using the mount option of uwsgi. In your config add the line
mount = /upload=<scriptname>
Solution courtesy of https://serverfault.com/questions/461946
Best and quick solution for me
location ~ /upload(/.*) {
include /etc/nginx/uwsgi_params;
uwsgi_pass unix:/var/sockets/upload.sock;
uwsgi_param PATH_INFO "$1";
}
Hope this can help you. cheers
Related
I am developing python programs and I have a flask file which runs them. Now I am trying to run flask automatically from Nginx and linking them with uWSGI. It's not working and getting stuck.
I followed this page.here is the link: https://vladikk.com/2013/09/12/serving-flask-with-nginx-on-ubuntu/
I have performed all the necessary steps and got 502 bad gateway error.
while executing
uswgi --ini /var/www/tg/tg_uswgi.ini
I am getting the following
[uSWGI] getting INI configuration from /var/www/tg/tg_uwsgi.ini
after this, I am not getting anything.when i run my server, it still gives me 502 Bad gateway.
this is my
tg_nginx.conf
server {
listen 80;
server_name localhost;
charset utf-8;
client_max_body_size 75M;
location / { try_files $uri #yourapplication; }
location #yourapplication {
include uwsgi_params;
uwsgi_pass unix:/var/www/tg/tg_uwsgi.sock;
}
}
this is my tg_uwsgi.ini
[uwsgi]
#application's base folder
base = /var/www/tg
#python module to import
app = fileforflk //fileforflk is my flask file which calls other python
//files
module = %(app)
home = %(base)/venv
pythonpath = %(base)
#socket file's location
socket = /var/www/demoapp/%n.sock
#permissions for the socket file
chmod-socket = 666
#the variable that holds a flask application inside the module imported at line #6
callable = app
#location of log files
logto = /var/log/uwsgi/%n.log
this is my flask file
from flask import Flask
import browser //python file the flask is calling
app = Flask(_name_)
#app.route('/test',methods= ['GET'])
def result():
return ("success")
if _name_ == '_main_':
app.run(host = '0.0.0.0',port=5000)
After getting INI configuration, the terminal is not showing anything and the server still returns bad gateway. please help me with this.
You should define:
socket = /var/www/demoapp/%n.sock
And :
uwsgi_pass unix:/var/www/tg/tg_uwsgi.sock;
should be matching. So for example, define:
socket = /var/www/tg/%n.sock
And :
sudo chown -R www-data:www-data /var/www/tg/
sudo chown -R www-data:www-data /var/log/uwsgi/
nginx config for the server (the main nginx one is the default one on debian 9):
server {
listen 80;
server_name subdomain.domain.com;
include /etc/nginx/mime.types;
location /galleries {
autoindex on;
alias /srv/galleries/;
}
location / {
include uwsgi_params;
uwsgi_pass unix:/tmp/scraper.sock;
}
}
uwsgi config:
[uwsgi]
module = wsgi:app
master = true
processes = 5
socket = /tmp/scraper.sock
chmod-socket = 777
uid = www-data
gid = www-data
vacuum = true
die-on-term = true
plugins = python3
py-autoreload = 1
If I try creating a route for /galleries/whatever, ie like this:
#app.route("/galleries/whatever")
def test():
return "Hello"
I'll just see the indexed files inside /galleries/whatever through nginx instead of going through flask.
Is there a way for me to force nginx to only handle requests if flask returns 404? Alternatively, is there a better way for me to serve files while still having them available under those urls? Keep in mind the /galleries folder is pretty big and generated by another program.
I run the server with "uwsgi --ini server.ini" and nothing else.
I am running a flask application using uwsgi and using nginx to serve the content.
vassal ini file:
[uwsgi]
chdir = /var/www/html/PyNLP/
;emperor = /var/www/html/PyNLP/
module = nltk_endpoint:app
master = true
processes = 5
socket = /tmp/PyNLP.sock
virtualenv = /var/www/html/PyNLP/nltkenv
mount = /PyNLP=nltk_endpoint:app
chmod-socket = 666
uid = www-data
gid = www-data
vacuum = true
die-on-term = true
enable-threads = true
;harakiri = 300
;buffer-size=65535
The project is contained in /var/www/html/PyNLP and contains the file nltk_endpoint.py along with the above .ini file
Now, when I run it without emperor:
uwsgi --ini PyNLP.ini --manage-script-name
It seems to be working fine when I try to access this flask API via a postman POST request. The URL looks like:
http://myIP:81/PyNLP/spellCheck
The first part /PyNLP is the mount point for the flask application and the last part /spellCheck is an app route in the project:
#app.route("/spellCheck", methods=["POST"])
def spellCheck():
req = request.get_json()
resp = jsonify(spell_check(req['text']))
return resp
The nginx config looks like:
location = /PyNLP { rewrite ^ /PyNLP/; }
location /PyNLP { try_files $uri #PyNLP; }
location #PyNLP {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
#try_files $uri $uri/ =404;
include uwsgi_params;
uwsgi_pass unix:/tmp/PyNLP.sock;
}
Without emperor this works just fine. But when I try to use:
uwsgi --emperor emperor/emperor.ini --manage-script-name
I get a 404 error for the url path on postman
Emperor ini file:
[uwsgi]
;emperor-tyrant = true
;emperor = %dvassals
;emperor-pidfile = %demperor.pid
;emperor-stats = %demperor.stat.sock
;vassals-include = %dvassals-default.ini
;touch-logrotate = %p
;touch-reload = %p
;touch-reload = %dvassals-default.ini
;log-date = true
;log-truncate = true
;logto =
emperor = /var/www/html/PyNLP/
;chdir = /var/www/html/PyNLP/
;mount = /PyNLP=nltk_endpoint:app
;buffer-size=65535
uid = www-data
gid = www-data
vacuum = true
die-on-term = true
uwsgi log for this request was :
[pid: 9812|app: 0|req: 1/1] 111.125.198.234 () {48 vars in 841 bytes} [Tue Jan 23 10:49:17 2018] POST /PyNLP/spellCheck => generated 233 bytes in 5 msecs (HTTP/1.1 404) 2 headers in 72 bytes (1 switches on core 0)announcing my loyalty to the Emperor...
and nginx/error.log as :
*43 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 111.125.198.234, server: _, request: "POST /PyNLP/spellCheck HTTP/1.1", upstream: "uwsgi://unix:/tmp/PyNLP.sock:", host: "XX.XX.XX.XX:81"
Similar questions on stackoverflow suggested either to change buffer-size in ini files, which did not help as well as to verify if post body is handled correctly, which I think is fine as well, since it worked with POST request just fine without emperor. I suspect it may be a mount or url path issue or a permission issue, but cant figure out why this wont work with emperor. Any ideas? Thanks in advance.
I am hosting a Flask app with nginx and uWSGI on a CentOS box. After a few hours, one of my pages goes down with a 500 internal server error Do you see anything jump out at you from my configs below?
My ers_portal_nginx.conf:
server {
listen 80;
server_name www.mydomain.com;
location / { try_files $uri #app; }
location #app {
include uwsgi_params;
uwsgi_pass unix:/home/metheuser/webapps/ers_portal/run_web_uwsgi.sock;
}
}
My ers_portal_uwsgi.ini:
[uwsgi]
#user info
uid = metheuser
gid = ers_group
#application's base folder
base = /home/metheuser/webapps/ers_portal
#python module to import
app = run_web
module = %(app)
home = %(base)/ers_portal_venv
pythonpath = %(base)
#socket file's location
socket = /home/metheuser/webapps/ers_portal/%n.sock
#permissions for the socket file
chmod-socket = 666
#uwsgi varible only, does not relate to your flask application
callable = app
#location of log files
logto = /home/metheuser/webapps/ers_portal/logs/%n.log
Relevant parts of my views.py
data_modification_time = None
data = None
def reload_data():
global data_modification_time, data, sites, column_names
filename = '/home/metheuser/webapps/ers_portal/app/static/' + ec.dd_filename
mtime = os.stat(filename).st_mtime
if data_modification_time != mtime:
data_modification_time = mtime
with open(filename) as f:
data = pickle.load(f)
return data
#a bunch of authentication stuff...
#app.route('/')
#app.route('/index')
def index():
return render_template("index.html",
title = 'Main',)
#app.route('/login', methods = ['GET', 'POST'])
def login():
login stuff...
#app.route('/my_table')
#login_required
def my_table():
print 'trying to access data table...'
data = reload_data()
return render_template("my_table.html",
title = "Rundata Viewer",
sts = sites,
cn = column_names,
data = data) # dictionary of data
I installed nginx via yum (yesterday)
I am using uWSGI installed in my venv via pip
I am on CentOS 6
I have everything set up very similar to here, meaning all the configs are in my app folder and /etc/nginx/nginx.conf is symlinked to.
My uwsgi log shows:
Wed Jun 11 17:20:01 2014 - uwsgi_response_writev_headers_and_body_do(): Broken pipe [core/writer.c line 287] during GET /whm-server-status (127.0.0.1)
IOError: write error
[pid: 9586|app: 0|req: 135/135] 127.0.0.1 () {24 vars in 292 bytes} [Wed Jun 11 17:20:01 2014] GET /whm-server-status => generated 0 bytes in 3 msecs (HTTP/1.0 404) 2 headers in 0 bytes (0 switches on core 0)
When its working, the print statement in the views "my_table" route prints into the log file. But not once it stops working.
Any ideas?
I'd like to have a static site in my root public_html directory, then Flask apps in their own subdirectories (e.g. public_html/foo). The static root directory functions as expected.
I have spent hours editing the nginx configuration to get the Flask apps working, but always end up back in the same place, namely that the following code always returns 'Bad Config' when I migrate to mysite/foo. I want it to return 'Hello World!'
If I alter the nginx configuration so that the server root is in public_html/foo, the Flask applications work as expected (i.e. mysite.com returns 'Hello World!'). In the following configuration, the Flask index still points to mysite.com when I believe it should point to mysite.com/foo
/etc/nginx/sites-enabled/mysite
upstream frontends {
# gunicorn
server 127.0.0.1:18000;
}
server {
listen 80;
server_name www.mysite.com;
rewrite ^/(.*) http://mysite.com$1 permanent;
}
server {
listen 80;
server_name mysite.com;
server_name_in_redirect off;
root /home/ubuntu/public_html/mysite;
access_log /home/ubuntu/logs/mysite/access.log;
error_log /home/ubuntu/logs/mysite/error.log;
location / {
index index.html;
}
location /foo {
try_files $uri #foo;
}
location #foo {
proxy_pass http://frontends;
break;
}
}
/home/ubuntu/public_html/mysite/foo/foo.py
from flask import Flask
from flask import render_template
app = Flask(__name__)
#app.route('/')
def index():
return 'Hello World!'
#app.route('/foo')
def test():
return 'Bad config'
#app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404
if __name__ == '__main__':
app.run()
/home/ubuntu/public_html/mysite/foo/deploy.py
workers = 2
bind = '127.0.0.1:18000'
proc_name = 'foo_gunicorn'
pidfile = 'foo.pid'
Flask is launched with gunicorn -c deploy.py foo:app
Update
Adding rewrite /foo/(.*) /$1 break; to the nginx location /foo block makes mysite/foo return 'Hello World', however all its links (such as those to the stylesheet from a template) still point to the site root (e.g. mysite/static/style.css instead of mysite/foo/static/style.css)
Got an answer from mitsuhiko (Flask lead dev):
http://flask.pocoo.org/snippets/35/
You need to define a ReverseProxied class in your Flask app and add several proxy-set-header lines to the location /foo block in the nginx config.